## Automatically generated incremental diff
## From:   linux-2.4.18-pre6
## To:     linux-2.4.18-pre7
## Robot:  $Id: make-incremental-diff,v 1.9 2001/12/10 00:06:56 hpa Exp $

diff -urN linux-2.4.18-pre6/CREDITS linux/CREDITS
--- linux-2.4.18-pre6/CREDITS	Wed Jan 23 15:04:29 2002
+++ linux/CREDITS	Wed Jan 23 15:04:31 2002
@@ -2653,6 +2653,16 @@
 S: Oldenburg
 S: Germany
 
+N: Robert Schwebel
+E: robert@schwebel.de
+W: http://www.schwebel.de
+D: Embedded hacker and book author,
+D: AMD Elan support for Linux
+S: Pengutronix
+S: Braunschweiger Strasse 79
+S: 31134 Hildesheim
+S: Germany
+
 N: Darren Senn
 E: sinster@darkwater.com
 D: Whatever I notice needs doing (so far: itimers, /proc)
diff -urN linux-2.4.18-pre6/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.4.18-pre6/Documentation/Configure.help	Wed Jan 23 15:04:29 2002
+++ linux/Documentation/Configure.help	Wed Jan 23 15:04:31 2002
@@ -2446,6 +2446,14 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+AH/ESP match support
+CONFIG_IP_NF_MATCH_AH_ESP
+  These two match extensions (`ah' and `esp') allow you to match a
+  range of SPIs inside AH or ESP headers of IPSec packets.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 TOS match support
 CONFIG_IP_NF_MATCH_TOS
   TOS matching allows you to match packets based on the Type Of
@@ -2613,6 +2621,19 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+ULOG target support
+CONFIG_IP_NF_TARGET_ULOG
+  This option adds a `ULOG' target, which allows you to create rules in
+  any iptables table. The packet is passed to a userspace logging
+  daemon using netlink multicast sockets; unlike the LOG target
+  which can only be viewed through syslog.
+
+  The apropriate userspace logging daemon (ulogd) may be obtained from
+  http://www.gnumonks.org/projects/ulogd
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 LOG target support
 CONFIG_IP_NF_TARGET_LOG
   This option adds a `LOG' target, which allows you to create rules in
@@ -2669,6 +2690,23 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+IPV6 queue handler (EXPERIMENTAL)
+CONFIG_IP6_NF_QUEUE
+
+  This option adds a queue handler to the kernel for IPv6
+  packets which lets us to receive the filtered packets
+  with QUEUE target using libiptc as we can do with
+  the IPv4 now.
+
+  (C) Fernando Anton 2001
+  IPv64 Project - Work based in IPv64 draft by Arturo Azcorra.
+  Universidad Carlos III de Madrid
+  Universidad Politecnica de Alcala de Henares
+  email: fanton@it.uc3m.es
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt. If unsure, say `N'.
+
 Owner match support
 CONFIG_IP6_NF_MATCH_OWNER
   Packet owner matching allows you to match locally-generated packets
@@ -3205,6 +3243,16 @@
   You should say Y here if you use XFree86 3.3.6 or 4.x and want to
   use GLX or DRI.  If unsure, say N.
 
+Intel 460GX support
+CONFIG_AGP_I460
+  This option gives you AGP support for the Intel 460GX chipset.  This
+  chipset, the first to support Intel Itanium processors, is new and
+  this option is correspondingly a little experimental.
+
+  If you don't have a 460GX based machine (such as BigSur) with an AGP 
+  slot then this option isn't going to do you much good.  If you're
+  dying to do Direct Rendering on IA-64, this is what you're looking for.
+
 Intel I810/I815 DC100/I810e support
 CONFIG_AGP_I810
   This option gives you AGP support for the Xserver on the Intel 810
@@ -3813,6 +3861,7 @@
    - "Pentium-4" for the Intel Pentium 4.
    - "K6" for the AMD K6, K6-II and K6-III (aka K6-3D).
    - "Athlon" for the AMD K7 family (Athlon/Duron/Thunderbird).
+   - "Elan" for the AMD Elan family (Elan SC400/SC410).
    - "Crusoe" for the Transmeta Crusoe series.
    - "Winchip-C6" for original IDT Winchip.
    - "Winchip-2" for IDT Winchip 2.
@@ -14891,6 +14940,18 @@
   Say Y here if you would like to be able to read the hard disk
   partition table format used by SGI machines.
 
+Intel EFI GUID partition support
+CONFIG_EFI_PARTITION
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned using EFI GPT.  Presently only useful on the
+  IA-64 platform.
+
+/dev/guid support (EXPERIMENTAL)
+CONFIG_DEVFS_GUID
+  Say Y here if you would like to access disks and partitions by
+  their Globally Unique Identifiers (GUIDs) which will appear as
+  symbolic links in /dev/guid.
+
 Ultrix partition table support
 CONFIG_ULTRIX_PARTITION
   Say Y here if you would like to be able to read the hard disk
@@ -23690,12 +23751,23 @@
 
   HP-simulator   For the HP simulator
                  (<http://software.hp.com/ia64linux/>).
-  SN1-simulator  For the SGI SN1 simulator.
+  SN1            For SGI SN1 Platforms.
+  SN2            For SGI SN2 Platforms.
   DIG-compliant  For DIG ("Developer's Interface Guide") compliant
                  system.
 
   If you don't know what to do, choose "generic".
 
+CONFIG_IA64_SGI_SN_SIM
+  Build a kernel that runs on both the SGI simulator AND on hardware.
+  There is a very slight performance penalty on hardware for including this
+  option.
+
+CONFIG_IA64_SGI_SN_DEBUG
+  This enables addition debug code that helps isolate
+  platform/kernel bugs. There is a small but measurable performance
+  degradation when this option is enabled.
+
 # Choice: pagesize
 Kernel page size
 CONFIG_IA64_PAGE_SIZE_4KB
@@ -23713,53 +23785,13 @@
 
   If you don't know what to do, choose 8KB.
 
-Enable Itanium A-step specific code
-CONFIG_ITANIUM_ASTEP_SPECIFIC
-  Select this option to build a kernel for an Itanium prototype system
-  with an A-step CPU.  You have an A-step CPU if the "revision" field
-  in /proc/cpuinfo is 0.
-
 Enable Itanium B-step specific code
 CONFIG_ITANIUM_BSTEP_SPECIFIC
   Select this option to build a kernel for an Itanium prototype system
-  with a B-step CPU.  You have a B-step CPU if the "revision" field in
-  /proc/cpuinfo has a value in the range from 1 to 4.
-
-Enable Itanium B0-step specific code
-CONFIG_ITANIUM_B0_SPECIFIC
-  Select this option to build a kernel for an Itanium prototype system
-  with a B0-step CPU.  You have a B0-step CPU if the "revision" field
-  in /proc/cpuinfo is 1.
-
-Enable Itanium C-step specific code
-CONFIG_ITANIUM_CSTEP_SPECIFIC
-  Select this option to build a kernel for an Itanium prototype system
-  with a C-step CPU.  You have a C-step CPU if the "revision" field in
-  /proc/cpuinfo is in the range of 5 to 8.
-
-Enable Itanium B1-step specific code
-CONFIG_ITANIUM_B1_SPECIFIC
-  Select this option to build a kernel for an Itanium prototype system
-  with a B1-step CPU.  You have a B1-step CPU if the "revision" field
-  in /proc/cpuinfo is 2.
-
-Enable Itanium B2-step specific code
-CONFIG_ITANIUM_B2_SPECIFIC
-  Select this option to build a kernel for an Itanium prototype system
-  with a B2-step CPU.  You have a B2-step CPU if the "revision" field
-  in /proc/cpuinfo is 3.
-
-Enable Itanium C0-step specific code
-CONFIG_ITANIUM_C0_SPECIFIC
-  Select this option to build a kernel for an Itanium prototype system
-  with a C0-step CPU.  You have a C0-step CPU if the "revision" field
-  in /proc/cpuinfo is 5.
-
-Force interrupt redirection
-CONFIG_IA64_HAVE_IRQREDIR
-  Select this option if you know that your system has the ability to
-  redirect interrupts to different CPUs.  Select N here if you're
-  unsure.
+  with a B-step CPU.  Only B3 step CPUs are supported.  You have a B3-step
+  CPU if the "revision" field in /proc/cpuinfo is equal to 4.  If the
+  "revision" field shows a number bigger than 4, you do not have to turn
+  on this option.
 
 Enable IA-64 Machine Check Abort
 CONFIG_IA64_MCA
@@ -23828,6 +23860,15 @@
   To use this option, you have to check that the "/proc file system
   support" (CONFIG_PROC_FS) is enabled, too.
 
+/proc/efi/vars support
+CONFIG_EFI_VARS
+  If you say Y here, you are able to get EFI (Extensible Firmware
+  Interface) variable information in /proc/efi/vars.  You may read,
+  write, create, and destroy EFI variables through this interface.
+
+  To use this option, you have to check that the "/proc file system
+  support" (CONFIG_PROC_FS) is enabled, too.
+
 Kernel support for IA-32 emulation
 CONFIG_IA32_SUPPORT
   IA64 processors can run IA32 (that is, x86) binaries by emulating
@@ -24298,6 +24339,16 @@
   If you are using GDB for remote debugging over a serial port and
   would like kernel messages to be formatted into GDB $O packets so
   that GDB prints them as program output, say 'Y'.
+
+802.1Q VLAN Support
+CONFIG_VLAN_8021Q
+  Select this and you will be able to create 802.1Q VLAN interfaces on your
+  ethernet interfaces.  802.1Q VLAN supports almost everything a regular
+  ethernet interface does, including firewalling, bridging, and of course
+  IP traffic.  You will need the 'vconfig' tool from the VLAN project in
+  order to effectively use VLANs.  See the VLAN web page for more
+  information:  http://www.candelatech.com/~greear/vlan.html  If unsure,
+  you can safely say 'N'.
 
 #
 # A couple of things I keep forgetting:
diff -urN linux-2.4.18-pre6/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt
--- linux-2.4.18-pre6/Documentation/kernel-parameters.txt	Wed Jun 20 11:21:33 2001
+++ linux/Documentation/kernel-parameters.txt	Wed Jan 23 15:04:31 2002
@@ -17,6 +17,7 @@
 	CD	Appropriate CD support is enabled.
 	DEVFS   devfs support is enabled. 
 	DRM	Direct Rendering Management support is enabled. 
+	EFI	EFI Partitioning (GPT) is enabled
 	EIDE	EIDE/ATAPI support is enabled.
 	FB	The frame buffer device is enabled.
 	HW	Appropriate hardware is enabled.
@@ -211,6 +212,9 @@
 	gc_3=		[HW,JOY]
  
 	gdth=		[HW,SCSI]
+
+	gpt             [EFI] Forces disk with valid GPT signature but
+			invalid Protective MBR to be treated as GPT.
 
 	gscd=		[HW,CD]
 
diff -urN linux-2.4.18-pre6/Makefile linux/Makefile
--- linux-2.4.18-pre6/Makefile	Wed Jan 23 15:04:29 2002
+++ linux/Makefile	Wed Jan 23 15:04:31 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 18
-EXTRAVERSION = -pre6
+EXTRAVERSION = -pre7
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -243,14 +243,14 @@
 
 include arch/$(ARCH)/Makefile
 
-export	CPPFLAGS CFLAGS AFLAGS
+export	CPPFLAGS CFLAGS CFLAGS_KERNEL AFLAGS AFLAGS_KERNEL
 
 export	NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS
 
 .S.s:
-	$(CPP) $(AFLAGS) -traditional -o $*.s $<
+	$(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -o $*.s $<
 .S.o:
-	$(CC) $(AFLAGS) -traditional -c -o $*.o $<
+	$(CC) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -c -o $*.o $<
 
 Version: dummy
 	@rm -f include/linux/compile.h
diff -urN linux-2.4.18-pre6/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- linux-2.4.18-pre6/arch/i386/boot/setup.S	Wed Jan 23 15:04:29 2002
+++ linux/arch/i386/boot/setup.S	Wed Jan 23 15:04:31 2002
@@ -42,6 +42,9 @@
  * if CX/DX have been changed in the e801 call and if so use AX/BX .
  * Michael Miller, April 2001 <michaelm@mjmm.org>
  *
+ * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes
+ * by Robert Schwebel, December 2001 <robert@schwebel.de>
+ *
  */
 
 #include <linux/config.h>
@@ -651,7 +654,18 @@
 #
 # Enable A20.  This is at the very best an annoying procedure.
 # A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin.
+# AMD Elan bug fix by Robert Schwebel.
 #
+
+#if defined(CONFIG_MELAN)
+	movb $0x02, %al			# alternate A20 gate
+	outb %al, $0x92			# this works on SC410/SC520
+a20_elan_wait:
+        call a20_test
+        jz a20_elan_wait
+	jmp a20_done
+#endif
+
 
 A20_TEST_LOOPS		=  32		# Iterations per wait
 A20_ENABLE_LOOPS	= 255		# Total loops to try		
diff -urN linux-2.4.18-pre6/arch/i386/config.in linux/arch/i386/config.in
--- linux-2.4.18-pre6/arch/i386/config.in	Fri Dec 21 09:41:53 2001
+++ linux/arch/i386/config.in	Wed Jan 23 15:04:31 2002
@@ -37,6 +37,7 @@
 	 Pentium-4				CONFIG_MPENTIUM4 \
 	 K6/K6-II/K6-III			CONFIG_MK6 \
 	 Athlon/Duron/K7			CONFIG_MK7 \
+	 Elan					CONFIG_MELAN \
 	 Crusoe					CONFIG_MCRUSOE \
 	 Winchip-C6				CONFIG_MWINCHIPC6 \
 	 Winchip-2				CONFIG_MWINCHIP2 \
@@ -125,6 +126,11 @@
    define_bool CONFIG_X86_USE_3DNOW y
    define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+fi
+if [ "$CONFIG_MELAN" = "y" ]; then
+   define_int  CONFIG_X86_L1_CACHE_SHIFT 4
+   define_bool CONFIG_X86_USE_STRING_486 y
+   define_bool CONFIG_X86_ALIGNMENT_16 y
 fi
 if [ "$CONFIG_MCYRIXIII" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
diff -urN linux-2.4.18-pre6/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- linux-2.4.18-pre6/arch/i386/kernel/apm.c	Fri Nov  9 13:58:02 2001
+++ linux/arch/i386/kernel/apm.c	Wed Jan 23 15:04:31 2002
@@ -39,6 +39,7 @@
  * Feb 2000, Version 1.13
  * Nov 2000, Version 1.14
  * Oct 2001, Version 1.15
+ * Jan 2002, Version 1.16
  *
  * History:
  *    0.6b: first version in official kernel, Linux 1.3.46
@@ -85,7 +86,7 @@
  *         change APM_NOINTS to CONFIG_APM_ALLOW_INTS
  *         remove dependency on CONFIG_PROC_FS
  *         Stephen Rothwell
- *    1.9: Fix small typo.  <laslo@ilo.opole.pl>
+ *    1.9: Fix small typo.  <laslo@wodip.opole.pl>
  *         Try to cope with BIOS's that need to have all display
  *         devices blanked and not just the first one.
  *         Ross Paterson <ross@soi.city.ac.uk>
@@ -164,8 +165,18 @@
  *         If an APM idle fails log it and idle sensibly
  *   1.15: Don't queue events to clients who open the device O_WRONLY.
  *         Don't expect replies from clients who open the device O_RDONLY.
- *         (Idea from Thomas Hood <jdthood at yahoo.co.uk>)
- *         Minor waitqueue cleanups.(John Fremlin <chief@bandits.org>)
+ *         (Idea from Thomas Hood <jdthood@mail.com>)
+ *         Minor waitqueue cleanups. (John Fremlin <chief@bandits.org>)
+ *   1.16: Fix idle calling. (Andreas Steinmetz <ast@domdv.de> et al.)
+ *         Notify listeners of standby or suspend events before notifying
+ *         drivers. Return EBUSY to ioctl() if suspend is rejected.
+ *         (Russell King <rmk@arm.linux.org.uk> and Thomas Hood)
+ *         Ignore first resume after we generate our own resume event
+ *         after a suspend (Thomas Hood <jdthood@mail.com>)
+ *         Daemonize now gets rid of our controlling terminal (sfr).
+ *         CONFIG_APM_CPU_IDLE now just affects the default value of
+ *         idle_threshold (sfr).
+ *         Change name of kernel apm daemon (as it no longer idles) (sfr).
  *
  * APM 1.1 Reference:
  *
@@ -238,6 +249,12 @@
  *	    [no-]power[-_]off		power off on shutdown
  *	    bounce[-_]interval=<n>	number of ticks to ignore suspend
  *	    				bounces
+ *          idle[-_]threshold=<n>       System idle percentage above which to
+ *                                      make APM BIOS idle calls. Set it to
+ *                                      100 to disable.
+ *          idle[-_]period=<n>          Period (in 1/100s of a second) over
+ *                                      which the idle percentage is
+ *                                      calculated.
  */
 
 /* KNOWN PROBLEM MACHINES:
@@ -341,15 +358,26 @@
 #define APM_BIOS_MAGIC		0x4101
 
 /*
+ * idle percentage above which bios idle calls are done
+ */
+#ifdef CONFIG_APM_CPU_IDLE
+#define DEFAULT_IDLE_THRESHOLD	95
+#else
+#define DEFAULT_IDLE_THRESHOLD	100
+#endif
+#define DEFAULT_IDLE_PERIOD	(100 / 3)
+
+/*
  * Local variables
  */
 static struct {
 	unsigned long	offset;
 	unsigned short	segment;
 }				apm_bios_entry;
-#ifdef CONFIG_APM_CPU_IDLE
 static int			clock_slowed;
-#endif
+static int			idle_threshold = DEFAULT_IDLE_THRESHOLD;
+static int			idle_period = DEFAULT_IDLE_PERIOD;
+static int			set_pm_idle;
 static int			suspends_pending;
 static int			standbys_pending;
 static int			waiting_for_resume;
@@ -388,7 +416,7 @@
 static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
 static struct apm_user *	user_list;
 
-static char			driver_version[] = "1.15";	/* no spaces */
+static char			driver_version[] = "1.16";	/* no spaces */
 
 /*
  *	APM event names taken from the APM 1.2 specification. These are
@@ -684,8 +712,6 @@
 	return set_power_state(APM_DEVICE_ALL, state);
 }
 
-#ifdef CONFIG_APM_CPU_IDLE
-
 /**
  *	apm_do_idle	-	perform power saving
  *
@@ -735,63 +761,89 @@
 	}
 }
 
-#if 0
-extern int hlt_counter;
-
 /*
- * If no process has been interested in this
- * CPU for some time, we want to wake up the
- * power management thread - we probably want
+ * If no process has really been interested in
+ * the CPU for some time, we want to call BIOS
+ * power management - we probably want
  * to conserve power.
  */
-#define HARD_IDLE_TIMEOUT (HZ/3)
+#define IDLE_CALC_LIMIT   (HZ * 100)
+#define IDLE_LEAKY_MAX    16
 
-/* This should wake up kapmd and ask it to slow the CPU */
-#define powermanagement_idle()  do { } while (0)
+static void (*sys_idle)(void);
+
+extern void default_idle(void);
 
 /**
  * apm_cpu_idle		-	cpu idling for APM capable Linux
  *
  * This is the idling function the kernel executes when APM is available. It 
- * tries to save processor time directly by using hlt instructions. A
- * separate apm thread tries to do the BIOS power management.
- *
- * N.B. This is curently not used for kernels 2.4.x.
+ * tries to do BIOS powermanagement based on the average system idle time.
+ * Furthermore it calls the system default idle routine.
  */
 
 static void apm_cpu_idle(void)
 {
-	unsigned int start_idle;
+	static int use_apm_idle = 0;
+	static unsigned int last_jiffies = 0;
+	static unsigned int last_stime = 0;
+
+	int apm_is_idle = 0;
+	unsigned int jiffies_since_last_check = jiffies - last_jiffies;
+	unsigned int t1;
+
+
+recalc:
+	if (jiffies_since_last_check > IDLE_CALC_LIMIT) {
+		use_apm_idle = 0;
+		last_jiffies = jiffies;
+		last_stime = current->times.tms_stime;
+	} else if (jiffies_since_last_check > idle_period) {
+		unsigned int idle_percentage;
+
+		idle_percentage = current->times.tms_stime - last_stime;
+		idle_percentage *= 100;
+		idle_percentage /= jiffies_since_last_check;
+		use_apm_idle = (idle_percentage > idle_threshold);
+		last_jiffies = jiffies;
+		last_stime = current->times.tms_stime;
+	}
+
+	t1 = IDLE_LEAKY_MAX;
+
+	while (!current->need_resched) {
+		if (use_apm_idle) {
+			unsigned int t;
 
-	start_idle = jiffies;
-	while (1) {
-		if (!current->need_resched) {
-			if (jiffies - start_idle < HARD_IDLE_TIMEOUT) {
-				if (!current_cpu_data.hlt_works_ok)
-					continue;
-				if (hlt_counter)
+			t = jiffies;
+			switch (apm_do_idle()) {
+			case 0: apm_is_idle = 1;
+				if (t != jiffies) {
+					if (t1) {
+						t1 = IDLE_LEAKY_MAX;
+						continue;
+					}
+				} else if (t1) {
+					t1--;
 					continue;
-				__cli();
-				if (!current->need_resched)
-					safe_halt();
-				else
-					__sti();
-				continue;
+				}
+				break;
+			case 1: apm_is_idle = 1;
+				break;
 			}
-
-			/*
-			 * Ok, do some power management - we've been idle for too long
-			 */
-			powermanagement_idle();
 		}
-
-		schedule();
-		check_pgt_cache();
-		start_idle = jiffies;
+		if (sys_idle)
+			sys_idle();
+		else
+			default_idle();
+		jiffies_since_last_check = jiffies - last_jiffies;
+		if (jiffies_since_last_check > idle_period)
+			goto recalc;
 	}
+
+	if (apm_is_idle)
+		apm_do_busy();
 }
-#endif
-#endif
 
 #ifdef CONFIG_SMP
 static int apm_magic(void * unused)
@@ -1133,57 +1185,42 @@
 #endif
 }
 
-static int send_event(apm_event_t event)
+static int suspend(int vetoable)
 {
-	switch (event) {
-	case APM_SYS_SUSPEND:
-	case APM_CRITICAL_SUSPEND:
-	case APM_USER_SUSPEND:
-		/* map all suspends to ACPI D3 */
-		if (pm_send_all(PM_SUSPEND, (void *)3)) {
-			if (event == APM_CRITICAL_SUSPEND) {
-				printk(KERN_CRIT
-					"apm: Critical suspend was vetoed, "
-					"expect armageddon\n" );
-				return 0;
-			}
+	int		err;
+	struct apm_user	*as;
+
+	if (pm_send_all(PM_SUSPEND, (void *)3)) {
+		/* Vetoed */
+		if (vetoable) {
 			if (apm_info.connection_version > 0x100)
 				apm_set_power_state(APM_STATE_REJECT);
-			return 0;
+			err = -EBUSY;
+			waiting_for_resume = 0;
+			printk(KERN_WARNING "apm: suspend was vetoed.\n");
+			goto out;
 		}
-		break;
-	case APM_NORMAL_RESUME:
-	case APM_CRITICAL_RESUME:
-		/* map all resumes to ACPI D0 */
-		(void) pm_send_all(PM_RESUME, (void *)0);
-		break;
+		printk(KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n");
 	}
-
-	return 1;
-}
-
-static int suspend(void)
-{
-	int		err;
-	struct apm_user	*as;
-
 	get_time_diff();
 	cli();
 	err = apm_set_power_state(APM_STATE_SUSPEND);
 	reinit_timer();
 	set_time();
+	sti();
 	if (err == APM_NO_ERROR)
 		err = APM_SUCCESS;
 	if (err != APM_SUCCESS)
 		apm_error("suspend", err);
-	send_event(APM_NORMAL_RESUME);
-	sti();
+	err = (err == APM_SUCCESS) ? 0 : -EIO;
+	pm_send_all(PM_RESUME, (void *)0);
 	queue_event(APM_NORMAL_RESUME, NULL);
+	ignore_normal_resume = 1;
+ out:
 	for (as = user_list; as != NULL; as = as->next) {
 		as->suspend_wait = 0;
-		as->suspend_result = ((err == APM_SUCCESS) ? 0 : -EIO);
+		as->suspend_result = err;
 	}
-	ignore_normal_resume = 1;
 	wake_up_interruptible(&apm_suspend_waitqueue);
 	return err;
 }
@@ -1192,6 +1229,7 @@
 {
 	int	err;
 
+	/* If needed, notify drivers here */
 	get_time_diff();
 	err = apm_set_power_state(APM_STATE_STANDBY);
 	if ((err != APM_SUCCESS) && (err != APM_NO_ERROR))
@@ -1235,17 +1273,13 @@
 		if (ignore_bounce
 		    && ((jiffies - last_resume) > bounce_interval))
 			ignore_bounce = 0;
-		if (ignore_normal_resume && (event != APM_NORMAL_RESUME))
-			ignore_normal_resume = 0;
 
 		switch (event) {
 		case APM_SYS_STANDBY:
 		case APM_USER_STANDBY:
-			if (send_event(event)) {
-				queue_event(event, NULL);
-				if (standbys_pending <= 0)
-					standby();
-			}
+			queue_event(event, NULL);
+			if (standbys_pending <= 0)
+				standby();
 			break;
 
 		case APM_USER_SUSPEND:
@@ -1270,12 +1304,10 @@
 			 */
 			if (waiting_for_resume)
 				return;
-			if (send_event(event)) {
-				queue_event(event, NULL);
-				waiting_for_resume = 1;
-				if (suspends_pending <= 0)
-					(void) suspend();
-			}
+			waiting_for_resume = 1;
+			queue_event(event, NULL);
+			if (suspends_pending <= 0)
+				(void) suspend(1);
 			break;
 
 		case APM_NORMAL_RESUME:
@@ -1287,16 +1319,17 @@
 			if ((event != APM_NORMAL_RESUME)
 			    || (ignore_normal_resume == 0)) {
 				set_time();
-				send_event(event);
+				pm_send_all(PM_RESUME, (void *)0);
 				queue_event(event, NULL);
 			}
+			ignore_normal_resume = 0;
 			break;
 
 		case APM_CAPABILITY_CHANGE:
 		case APM_LOW_BATTERY:
 		case APM_POWER_STATUS_CHANGE:
-			send_event(event);
 			queue_event(event, NULL);
+			/* If needed, notify drivers here */
 			break;
 
 		case APM_UPDATE_TIME:
@@ -1304,12 +1337,10 @@
 			break;
 
 		case APM_CRITICAL_SUSPEND:
-			send_event(event);
 			/*
-			 * We can only hope it worked - we are not allowed
-			 * to reject a critical suspend.
+			 * We are not allowed to reject a critical suspend.
 			 */
-			(void) suspend();
+			(void) suspend(0);
 			break;
 		}
 	}
@@ -1337,63 +1368,24 @@
 
 /*
  * This is the APM thread main loop.
- *
- * Check whether we're the only running process to
- * decide if we should just power down.
- *
  */
-#define system_idle() (nr_running == 1)
 
 static void apm_mainloop(void)
 {
-	int timeout = HZ;
 	DECLARE_WAITQUEUE(wait, current);
 
 	add_wait_queue(&apm_waitqueue, &wait);
 	set_current_state(TASK_INTERRUPTIBLE);
 	for (;;) {
-		/* Nothing to do, just sleep for the timeout */
-		timeout = 2 * timeout;
-		if (timeout > APM_CHECK_TIMEOUT)
-			timeout = APM_CHECK_TIMEOUT;
-		schedule_timeout(timeout);
+		schedule_timeout(APM_CHECK_TIMEOUT);
 		if (exit_kapmd)
 			break;
-
 		/*
 		 * Ok, check all events, check for idle (and mark us sleeping
 		 * so as not to count towards the load average)..
 		 */
 		set_current_state(TASK_INTERRUPTIBLE);
 		apm_event_handler();
-#ifdef CONFIG_APM_CPU_IDLE
-		if (!system_idle())
-			continue;
-		
-		/*
-		 *	If we can idle...
-		 */
-		if (apm_do_idle() != -1) {
-			unsigned long start = jiffies;
-			while ((!exit_kapmd) && system_idle()) {
-				if (apm_do_idle()) {
-					set_current_state(TASK_INTERRUPTIBLE);
-					/* APM needs us to snooze .. either
-					   the BIOS call failed (-1) or it
-					   slowed the clock (1). We sleep
-					   until it talks to us again */
-					schedule_timeout(1);
-				}
-				if ((jiffies - start) > APM_CHECK_TIMEOUT) {
-					apm_event_handler();
-					start = jiffies;
-				}
-			}
-			apm_do_busy();
-			apm_event_handler();
-			timeout = 1;
-		}
-#endif
 	}
 	remove_wait_queue(&apm_waitqueue, &wait);
 }
@@ -1479,9 +1471,7 @@
 			as->standbys_read--;
 			as->standbys_pending--;
 			standbys_pending--;
-		} else if (!send_event(APM_USER_STANDBY))
-			return -EAGAIN;
-		else
+		} else
 			queue_event(APM_USER_STANDBY, as);
 		if (standbys_pending <= 0)
 			standby();
@@ -1491,13 +1481,10 @@
 			as->suspends_read--;
 			as->suspends_pending--;
 			suspends_pending--;
-		} else if (!send_event(APM_USER_SUSPEND))
-			return -EAGAIN;
-		else
+		} else
 			queue_event(APM_USER_SUSPEND, as);
 		if (suspends_pending <= 0) {
-			if (suspend() != APM_SUCCESS)
-				return -EIO;
+			return suspend(1);
 		} else {
 			as->suspend_wait = 1;
 			wait_event_interruptible(apm_suspend_waitqueue,
@@ -1528,7 +1515,7 @@
 	if (as->suspends_pending > 0) {
 		suspends_pending -= as->suspends_pending;
 		if (suspends_pending <= 0)
-			(void) suspend();
+			(void) suspend(1);
 	}
 	if (user_list == as)
 		user_list = as->next;
@@ -1676,9 +1663,8 @@
 
 	daemonize();
 
-	strcpy(current->comm, "kapm-idled");
+	strcpy(current->comm, "kapmd");
 	sigfillset(&current->blocked);
-	current->tty = NULL;	/* get rid of controlling tty */
 
 	if (apm_info.connection_version == 0) {
 		apm_info.connection_version = apm_info.bios.version;
@@ -1797,7 +1783,14 @@
 		if ((strncmp(str, "bounce-interval=", 16) == 0) ||
 		    (strncmp(str, "bounce_interval=", 16) == 0))
 			bounce_interval = simple_strtol(str + 16, NULL, 0);
-		invert = (strncmp(str, "no-", 3) == 0);
+		if ((strncmp(str, "idle-threshold=", 15) == 0) ||
+		    (strncmp(str, "idle_threshold=", 15) == 0))
+			idle_threshold = simple_strtol(str + 15, NULL, 0);
+		if ((strncmp(str, "idle-period=", 12) == 0) ||
+		    (strncmp(str, "idle_period=", 12) == 0))
+			idle_threshold = simple_strtol(str + 15, NULL, 0);
+		invert = (strncmp(str, "no-", 3) == 0) ||
+			(strncmp(str, "no_", 3) == 0);
 		if (invert)
 			str += 3;
 		if (strncmp(str, "debug", 5) == 0)
@@ -1968,6 +1961,14 @@
 
 	misc_register(&apm_device);
 
+	if (HZ != 100)
+		idle_period = (idle_period * HZ) / 100;
+	if (idle_threshold < 100) {
+		sys_idle = pm_idle;
+		pm_idle  = apm_cpu_idle;
+		set_pm_idle = 1;
+	}
+
 	return 0;
 }
 
@@ -1975,6 +1976,8 @@
 {
 	int	error;
 
+	if (set_pm_idle)
+		pm_idle = sys_idle;
 	if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0)
 	    && (apm_info.connection_version > 0x0100)) {
 		error = apm_engage_power_management(APM_DEVICE_ALL, 0);
@@ -2012,5 +2015,11 @@
 MODULE_PARM(realmode_power_off, "i");
 MODULE_PARM_DESC(realmode_power_off,
 		"Switch to real mode before powering off");
+MODULE_PARM(idle_threshold, "i");
+MODULE_PARM_DESC(idle_threshold,
+	"System idle percentage above which to make APM BIOS idle calls");
+MODULE_PARM(idle_period, "i");
+MODULE_PARM_DESC(idle_period,
+	"Period (in sec/100) over which to caculate the idle percentage");
 
 EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.18-pre6/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- linux-2.4.18-pre6/arch/i386/kernel/i386_ksyms.c	Tue Nov 13 09:13:20 2001
+++ linux/arch/i386/kernel/i386_ksyms.c	Wed Jan 23 15:04:31 2002
@@ -35,6 +35,8 @@
 #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
 extern void machine_real_restart(unsigned char *, int);
 EXPORT_SYMBOL(machine_real_restart);
+extern void default_idle(void);
+EXPORT_SYMBOL(default_idle);
 #endif
 
 #ifdef CONFIG_SMP
diff -urN linux-2.4.18-pre6/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- linux-2.4.18-pre6/arch/i386/kernel/process.c	Thu Oct  4 18:42:54 2001
+++ linux/arch/i386/kernel/process.c	Wed Jan 23 15:04:31 2002
@@ -77,7 +77,7 @@
  * We use this if we don't have any better
  * idle routine..
  */
-static void default_idle(void)
+void default_idle(void)
 {
 	if (current_cpu_data.hlt_works_ok && !hlt_counter) {
 		__cli();
diff -urN linux-2.4.18-pre6/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- linux-2.4.18-pre6/arch/i386/kernel/setup.c	Wed Jan 23 15:04:29 2002
+++ linux/arch/i386/kernel/setup.c	Wed Jan 23 15:04:31 2002
@@ -329,6 +329,10 @@
 	{ "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
 	{ "fpu", 0xf0, 0xff, IORESOURCE_BUSY }
 };
+#ifdef CONFIG_ELAN
+standard_io_resources[1] = { "pic1", 0x20, 0x21, IORESOURCE_BUSY };
+standard_io_resources[5] = { "pic2", 0xa0, 0xa1, IORESOURCE_BUSY };
+#endif
 
 #define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
 
diff -urN linux-2.4.18-pre6/drivers/block/genhd.c linux/drivers/block/genhd.c
--- linux-2.4.18-pre6/drivers/block/genhd.c	Wed Oct 17 14:46:29 2001
+++ linux/drivers/block/genhd.c	Wed Jan 23 15:04:32 2002
@@ -33,6 +33,7 @@
  *	the only reason this is exported is source compatiblity.
  */
 /*static*/ struct gendisk *gendisk_head;
+static struct gendisk *gendisk_array[MAX_BLKDEV];
 
 EXPORT_SYMBOL(gendisk_head);
 
@@ -65,6 +66,7 @@
 			goto out;
 		}
 	}
+	gendisk_array[gp->major] = gp;
 	gp->next = gendisk_head;
 	gendisk_head = gp;
 out:
@@ -87,6 +89,7 @@
 	struct gendisk **gpp;
 
 	write_lock(&gendisk_lock);
+	gendisk_array[gp->major] = NULL;
 	for (gpp = &gendisk_head; *gpp; gpp = &((*gpp)->next))
 		if (*gpp == gp)
 			break;
@@ -112,11 +115,15 @@
 	int maj = MAJOR(dev);
 
 	read_lock(&gendisk_lock);
+	if ((gp = gendisk_array[maj]))
+		goto out;
+
+	/* This is needed for early 2.4 source compatiblity.  --hch */
 	for (gp = gendisk_head; gp; gp = gp->next)
 		if (gp->major == maj)
 			break;
+out:
 	read_unlock(&gendisk_lock);
-
 	return gp;
 }
 
diff -urN linux-2.4.18-pre6/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c
--- linux-2.4.18-pre6/drivers/char/agp/agpgart_be.c	Wed Jan 23 15:04:29 2002
+++ linux/drivers/char/agp/agpgart_be.c	Wed Jan 23 15:04:32 2002
@@ -1857,6 +1857,9 @@
        agp_bridge.free_by_type = agp_generic_free_by_type;
        agp_bridge.agp_alloc_page = agp_generic_alloc_page;
        agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+       agp_bridge.suspend = agp_generic_suspend;
+       agp_bridge.resume = agp_generic_resume;
+       agp_bridge.cant_use_aperture = 0;
 
        return 0;
 
@@ -1887,7 +1890,9 @@
        agp_bridge.free_by_type = agp_generic_free_by_type;
        agp_bridge.agp_alloc_page = agp_generic_alloc_page;
        agp_bridge.agp_destroy_page = agp_generic_destroy_page;
-
+       agp_bridge.suspend = agp_generic_suspend;
+       agp_bridge.resume = agp_generic_resume;
+       agp_bridge.cant_use_aperture = 0;
        return 0;
 
        (void) pdev; /* unused */
diff -urN linux-2.4.18-pre6/drivers/char/joystick/emu10k1-gp.c linux/drivers/char/joystick/emu10k1-gp.c
--- linux-2.4.18-pre6/drivers/char/joystick/emu10k1-gp.c	Fri Dec 21 09:41:54 2001
+++ linux/drivers/char/joystick/emu10k1-gp.c	Wed Jan 23 15:04:32 2002
@@ -52,6 +52,7 @@
 	
 static struct pci_device_id emu_tbl[] __devinitdata = {
 	{ 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live! gameport */
+        { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy! gameport */
 	{ 0, }
 };
 
diff -urN linux-2.4.18-pre6/drivers/sbus/char/riowatchdog.c linux/drivers/sbus/char/riowatchdog.c
--- linux-2.4.18-pre6/drivers/sbus/char/riowatchdog.c	Wed Jan 23 15:04:29 2002
+++ linux/drivers/sbus/char/riowatchdog.c	Wed Jan 23 15:04:33 2002
@@ -1,4 +1,4 @@
-/* $Id: riowatchdog.c,v 1.3 2001/10/08 22:19:51 davem Exp $
+/* $Id: riowatchdog.c,v 1.3.2.2 2002/01/23 18:48:02 davem Exp $
  * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -131,6 +131,7 @@
 	       	WDIOF_SETTIMEOUT, 0, "Natl. Semiconductor PC97317"
 	};
 	unsigned int options;
+	int new_margin;
 
 	switch (cmd) {
 	case WDIOC_GETSUPPORT:
diff -urN linux-2.4.18-pre6/drivers/video/tdfxfb.c linux/drivers/video/tdfxfb.c
--- linux-2.4.18-pre6/drivers/video/tdfxfb.c	Fri Dec 21 09:41:55 2001
+++ linux/drivers/video/tdfxfb.c	Wed Jan 23 15:04:33 2002
@@ -401,7 +401,7 @@
 /*
  *  Internal routines
  */
-static void tdfxfb_set_par(const struct tdfxfb_par* par,
+static void tdfxfb_set_par(struct tdfxfb_par* par,
 			   struct fb_info_tdfx* 
 			   info);
 static int  tdfxfb_decode_var(const struct fb_var_screeninfo *var,
@@ -1275,7 +1275,7 @@
 
 /* ------------------------------------------------------------------------- */
 
-static void tdfxfb_set_par(const struct tdfxfb_par* par,
+static void tdfxfb_set_par(struct tdfxfb_par* par,
 			   struct fb_info_tdfx*     info) {
   struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
   struct banshee_reg reg;
@@ -1290,6 +1290,28 @@
 
   cpp = (par->bpp + 7)/8;
   
+  reg.vidcfg = 
+    VIDCFG_VIDPROC_ENABLE |
+    VIDCFG_DESK_ENABLE    |
+    VIDCFG_CURS_X11 |
+    ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) |
+    (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
+
+  /* PLL settings */
+  freq = par->pixclock;
+
+  reg.dacmode = 0;
+  reg.vidcfg  &= ~VIDCFG_2X;
+
+  if(freq > i->max_pixclock/2) {
+    freq = freq > i->max_pixclock ? i->max_pixclock : freq;
+    reg.dacmode |= DACMODE_2X;
+    reg.vidcfg  |= VIDCFG_2X;
+    par->hdispend >>= 1;
+    par->hsyncsta >>= 1;
+    par->hsyncend >>= 1;
+    par->htotal   >>= 1;
+  }
   wd = (par->hdispend >> 3) - 1;
 
   hd  = (par->hdispend >> 3) - 1;
@@ -1356,9 +1378,7 @@
   reg.crt[0x02] = hbs;
   reg.crt[0x03] = 0x80 | (hbe & 0x1f);
   reg.crt[0x04] = hs;
-  reg.crt[0x05] = 
-    ((hbe & 0x20) << 2) | 
-    (he & 0x1f);
+  reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
   reg.crt[0x06] = vt;
   reg.crt[0x07] = 
     ((vs & 0x200) >> 2) |
@@ -1380,9 +1400,7 @@
   reg.crt[0x0e] = 0x00;
   reg.crt[0x0f] = 0x00;
   reg.crt[0x10] = vs;
-  reg.crt[0x11] = 
-    (ve & 0x0f) |
-    0x20;
+  reg.crt[0x11] = (ve & 0x0f) | 0x20;
   reg.crt[0x12] = vd;
   reg.crt[0x13] = wd;
   reg.crt[0x14] = 0x00;
@@ -1411,13 +1429,6 @@
     VGAINIT0_EXTSHIFTOUT;
   reg.vgainit1 = tdfx_inl(VGAINIT1) & 0x1fffff;
 
-  reg.vidcfg = 
-    VIDCFG_VIDPROC_ENABLE |
-    VIDCFG_DESK_ENABLE    |
-    VIDCFG_CURS_X11 |
-    ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) |
-    (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
-  
   fb_info.cursor.enable=reg.vidcfg | VIDCFG_HWCURSOR_ENABLE;
   fb_info.cursor.disable=reg.vidcfg;
    
@@ -1433,16 +1444,6 @@
   reg.srcbase   = reg.startaddr;
   reg.dstbase   = reg.startaddr;
 
-  /* PLL settings */
-  freq = par->pixclock;
-
-  reg.dacmode &= ~DACMODE_2X;
-  reg.vidcfg  &= ~VIDCFG_2X;
-  if(freq > i->max_pixclock/2) {
-    freq = freq > i->max_pixclock ? i->max_pixclock : freq;
-    reg.dacmode |= DACMODE_2X;
-    reg.vidcfg  |= VIDCFG_2X;
-  }
   reg.vidpll = do_calc_pll(freq, &fout);
 #if 0
   reg.mempll = do_calc_pll(..., &fout);
@@ -1473,9 +1474,13 @@
 #endif
 
   do_write_regs(&reg);
-
+  if (reg.vidcfg & VIDCFG_2X) {
+    par->hdispend <<= 1;
+    par->hsyncsta <<= 1;
+    par->hsyncend <<= 1;
+    par->htotal   <<= 1;
+  }
   i->current_par = *par;
-
 }
 
 static int tdfxfb_decode_var(const struct fb_var_screeninfo* var,
diff -urN linux-2.4.18-pre6/fs/adfs/dir_f.c linux/fs/adfs/dir_f.c
--- linux-2.4.18-pre6/fs/adfs/dir_f.c	Mon Sep 18 15:14:06 2000
+++ linux/fs/adfs/dir_f.c	Wed Jan 23 15:04:33 2002
@@ -193,7 +193,7 @@
 			goto release_buffers;
 		}
 
-		dir->bh[blk] = bread(sb->s_dev, phys, sb->s_blocksize);
+		dir->bh[blk] = sb_bread(sb, phys);
 		if (!dir->bh[blk])
 			goto release_buffers;
 	}
diff -urN linux-2.4.18-pre6/fs/adfs/dir_fplus.c linux/fs/adfs/dir_fplus.c
--- linux-2.4.18-pre6/fs/adfs/dir_fplus.c	Mon Sep 18 15:14:06 2000
+++ linux/fs/adfs/dir_fplus.c	Wed Jan 23 15:04:33 2002
@@ -35,7 +35,7 @@
 		goto out;
 	}
 
-	dir->bh[0] = bread(sb->s_dev, block, sb->s_blocksize);
+	dir->bh[0] = sb_bread(sb, block);
 	if (!dir->bh[0])
 		goto out;
 	dir->nr_buffers += 1;
@@ -60,7 +60,7 @@
 			goto out;
 		}
 
-		dir->bh[blk] = bread(sb->s_dev, block, sb->s_blocksize);
+		dir->bh[blk] = sb_bread(sb, block);
 		if (!dir->bh[blk])
 			goto out;
 		dir->nr_buffers = blk;
diff -urN linux-2.4.18-pre6/fs/adfs/super.c linux/fs/adfs/super.c
--- linux-2.4.18-pre6/fs/adfs/super.c	Thu Oct 25 13:53:53 2001
+++ linux/fs/adfs/super.c	Wed Jan 23 15:04:33 2002
@@ -263,7 +263,7 @@
 		dm[zone].dm_startbit = 0;
 		dm[zone].dm_endbit   = zone_size;
 		dm[zone].dm_startblk = zone * zone_size - ADFS_DR_SIZE_BITS;
-		dm[zone].dm_bh       = bread(sb->s_dev, map_addr, sb->s_blocksize);
+		dm[zone].dm_bh       = sb_bread(sb, map_addr);
 
 		if (!dm[zone].dm_bh) {
 			adfs_error(sb, "unable to read map");
@@ -319,8 +319,9 @@
 	if (parse_options(sb, data))
 		goto error;
 
+	sb->s_blocksize = BLOCK_SIZE;
 	set_blocksize(dev, BLOCK_SIZE);
-	if (!(bh = bread(dev, ADFS_DISCRECORD / BLOCK_SIZE, BLOCK_SIZE))) {
+	if (!(bh = sb_bread(sb, ADFS_DISCRECORD / BLOCK_SIZE))) {
 		adfs_error(sb, "unable to read superblock");
 		goto error;
 	}
@@ -354,7 +355,7 @@
 
 		brelse(bh);
 		set_blocksize(dev, sb->s_blocksize);
-		bh = bread(dev, ADFS_DISCRECORD / sb->s_blocksize, sb->s_blocksize);
+		bh = sb_bread(sb, ADFS_DISCRECORD / sb->s_blocksize);
 		if (!bh) {
 			adfs_error(sb, "couldn't read superblock on "
 				"2nd try.");
diff -urN linux-2.4.18-pre6/fs/affs/Changes linux/fs/affs/Changes
--- linux-2.4.18-pre6/fs/affs/Changes	Tue Sep 11 08:19:35 2001
+++ linux/fs/affs/Changes	Wed Jan 23 15:04:33 2002
@@ -28,6 +28,12 @@
 
 Please direct bug reports to: zippel@linux-m68k.org
 
+Version 3.19
+------------
+
+- sizeof changes from Kernel Janitor Project
+- several bug fixes found with fsx
+
 Version 3.18
 ------------
 
diff -urN linux-2.4.18-pre6/fs/affs/bitmap.c linux/fs/affs/bitmap.c
--- linux-2.4.18-pre6/fs/affs/bitmap.c	Wed Apr 25 14:57:09 2001
+++ linux/fs/affs/bitmap.c	Wed Jan 23 15:04:33 2002
@@ -292,7 +292,7 @@
 	AFFS_SB->s_bmap_bits = sb->s_blocksize * 8 - 32;
 	AFFS_SB->s_bmap_count = (AFFS_SB->s_partition_size - AFFS_SB->s_reserved +
 				 AFFS_SB->s_bmap_bits - 1) / AFFS_SB->s_bmap_bits;
-	size = AFFS_SB->s_bmap_count * sizeof(struct affs_bm_info);
+	size = AFFS_SB->s_bmap_count * sizeof(*bm);
 	bm = AFFS_SB->s_bitmap = kmalloc(size, GFP_KERNEL);
 	if (!AFFS_SB->s_bitmap) {
 		printk(KERN_ERR "AFFS: Bitmap allocation failed\n");
diff -urN linux-2.4.18-pre6/fs/affs/file.c linux/fs/affs/file.c
--- linux-2.4.18-pre6/fs/affs/file.c	Tue Sep 11 08:19:35 2001
+++ linux/fs/affs/file.c	Wed Jan 23 15:04:33 2002
@@ -510,7 +510,7 @@
 static int
 affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
 {
-	struct inode *inode = file->f_dentry->d_inode;
+	struct inode *inode = page->mapping->host;
 	struct super_block *sb = inode->i_sb;
 	struct buffer_head *bh;
 	char *data;
@@ -518,6 +518,8 @@
 	u32 tmp;
 
 	pr_debug("AFFS: read_page(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
+	if (from > to || to > PAGE_CACHE_SIZE)
+		BUG();
 	data = page_address(page);
 	bsize = AFFS_SB->s_data_blksize;
 	tmp = (page->index << PAGE_CACHE_SHIFT) + from;
@@ -528,7 +530,9 @@
 		bh = affs_bread_ino(inode, bidx, 0);
 		if (IS_ERR(bh))
 			return PTR_ERR(bh);
-		tmp = min(bsize - boff, from - to);
+		tmp = min(bsize - boff, to - from);
+		if (from + tmp > to || tmp > bsize)
+			BUG();
 		memcpy(data + from, AFFS_DATA(bh) + boff, tmp);
 		affs_brelse(bh);
 		bidx++;
@@ -539,9 +543,8 @@
 }
 
 static int
-affs_extent_file_ofs(struct file *file, u32 newsize)
+affs_extent_file_ofs(struct inode *inode, u32 newsize)
 {
-	struct inode *inode = file->f_dentry->d_inode;
 	struct super_block *sb = inode->i_sb;
 	struct buffer_head *bh, *prev_bh;
 	u32 bidx, boff;
@@ -551,7 +554,7 @@
 	pr_debug("AFFS: extent_file(%u, %d)\n", (u32)inode->i_ino, newsize);
 	bsize = AFFS_SB->s_data_blksize;
 	bh = NULL;
-	size = inode->i_size;
+	size = AFFS_INODE->mmu_private;
 	bidx = size / bsize;
 	boff = size % bsize;
 	if (boff) {
@@ -559,6 +562,8 @@
 		if (IS_ERR(bh))
 			return PTR_ERR(bh);
 		tmp = min(bsize - boff, newsize - size);
+		if (boff + tmp > bsize || tmp > bsize)
+			BUG();
 		memset(AFFS_DATA(bh) + boff, 0, tmp);
 		AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
 		affs_fix_checksum(sb, bh);
@@ -577,18 +582,21 @@
 		if (IS_ERR(bh))
 			goto out;
 		tmp = min(bsize, newsize - size);
+		if (tmp > bsize)
+			BUG();
 		AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
 		AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
 		AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
 		AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
 		affs_fix_checksum(sb, bh);
+		bh->b_state &= ~(1UL << BH_New);
 		mark_buffer_dirty_inode(bh, inode);
 		if (prev_bh) {
 			u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
 			if (tmp)
-				affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+				affs_warning(sb, "extent_file_ofs", "next block already set for %d (%d)", bidx, tmp);
 			AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
-			affs_adjust_checksum(prev_bh, bidx - tmp);
+			affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
 			mark_buffer_dirty_inode(prev_bh, inode);
 			affs_brelse(prev_bh);
 		}
@@ -596,7 +604,7 @@
 		bidx++;
 	}
 	affs_brelse(bh);
-	inode->i_size = AFFS_INODE->mmu_private = size;
+	inode->i_size = AFFS_INODE->mmu_private = newsize;
 	return 0;
 
 out:
@@ -607,7 +615,7 @@
 static int
 affs_readpage_ofs(struct file *file, struct page *page)
 {
-	struct inode *inode = file->f_dentry->d_inode;
+	struct inode *inode = page->mapping->host;
 	u32 to;
 	int err;
 
@@ -627,22 +635,22 @@
 
 static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
 {
-	struct inode *inode = file->f_dentry->d_inode;
+	struct inode *inode = page->mapping->host;
 	u32 size, offset;
 	u32 tmp;
 	int err = 0;
 
 	pr_debug("AFFS: prepare_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
-	if (Page_Uptodate(page))
-		return 0;
-
-	size = inode->i_size;
 	offset = page->index << PAGE_CACHE_SHIFT;
-	if (offset + from > size) {
-		err = affs_extent_file_ofs(file, offset + from);
+	if (offset + from > AFFS_INODE->mmu_private) {
+		err = affs_extent_file_ofs(inode, offset + from);
 		if (err)
 			return err;
 	}
+	size = inode->i_size;
+
+	if (Page_Uptodate(page))
+		return 0;
 
 	if (from) {
 		err = affs_do_readpage_ofs(file, page, 0, from);
@@ -653,7 +661,7 @@
 		memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to);
 		if (size > offset + to) {
 			if (size < offset + PAGE_CACHE_SIZE)
-				tmp = size & PAGE_CACHE_MASK;
+				tmp = size & ~PAGE_CACHE_MASK;
 			else
 				tmp = PAGE_CACHE_SIZE;
 			err = affs_do_readpage_ofs(file, page, to, tmp);
@@ -664,7 +672,7 @@
 
 static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
 {
-	struct inode *inode = file->f_dentry->d_inode;
+	struct inode *inode = page->mapping->host;
 	struct super_block *sb = inode->i_sb;
 	struct buffer_head *bh, *prev_bh;
 	char *data;
@@ -686,6 +694,8 @@
 		if (IS_ERR(bh))
 			return PTR_ERR(bh);
 		tmp = min(bsize - boff, to - from);
+		if (boff + tmp > bsize || tmp > bsize)
+			BUG();
 		memcpy(AFFS_DATA(bh) + boff, data + from, tmp);
 		AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
 		affs_fix_checksum(sb, bh);
@@ -710,12 +720,13 @@
 			AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
 			AFFS_DATA_HEAD(bh)->size = cpu_to_be32(bsize);
 			AFFS_DATA_HEAD(bh)->next = 0;
+			bh->b_state &= ~(1UL << BH_New);
 			if (prev_bh) {
 				u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
 				if (tmp)
-					affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+					affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp);
 				AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
-				affs_adjust_checksum(prev_bh, bidx - tmp);
+				affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
 				mark_buffer_dirty_inode(prev_bh, inode);
 			}
 		}
@@ -732,6 +743,8 @@
 		if (IS_ERR(bh))
 			goto out;
 		tmp = min(bsize, to - from);
+		if (tmp > bsize)
+			BUG();
 		memcpy(AFFS_DATA(bh), data + from, tmp);
 		if (bh->b_state & (1UL << BH_New)) {
 			AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
@@ -739,12 +752,13 @@
 			AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
 			AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
 			AFFS_DATA_HEAD(bh)->next = 0;
+			bh->b_state &= ~(1UL << BH_New);
 			if (prev_bh) {
 				u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
 				if (tmp)
-					affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+					affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp);
 				AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
-				affs_adjust_checksum(prev_bh, bidx - tmp);
+				affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
 				mark_buffer_dirty_inode(prev_bh, inode);
 			}
 		} else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp)
@@ -808,7 +822,8 @@
 	struct buffer_head *ext_bh;
 	int i;
 
-	pr_debug("AFFS: truncate(inode=%d, size=%u)\n", (u32)inode->i_ino, (u32)inode->i_size);
+	pr_debug("AFFS: truncate(inode=%d, oldsize=%u, newsize=%u)\n",
+		 (u32)inode->i_ino, (u32)AFFS_INODE->mmu_private, (u32)inode->i_size);
 
 	last_blk = 0;
 	ext = 0;
@@ -839,10 +854,19 @@
 
 	// lock cache
 	ext_bh = affs_get_extblock(inode, ext);
+	if (IS_ERR(ext_bh)) {
+		affs_warning(sb, "truncate", "unexpected read error for ext block %u (%d)",
+			     ext, PTR_ERR(ext_bh));
+		return;
+	}
 	if (AFFS_INODE->i_lc) {
 		/* clear linear cache */
-		for (i = (ext + 1) >> AFFS_INODE->i_lc_shift; i < AFFS_LC_SIZE; i++)
-			AFFS_INODE->i_lc[i] = 0;
+		i = (ext + 1) >> AFFS_INODE->i_lc_shift;
+		if (AFFS_INODE->i_lc_size > i) {
+			AFFS_INODE->i_lc_size = i;
+			for (; i < AFFS_LC_SIZE; i++)
+				AFFS_INODE->i_lc[i] = 0;
+		}
 		/* clear associative cache */
 		for (i = 0; i < AFFS_AC_SIZE; i++)
 			if (AFFS_INODE->i_ac[i].ext >= ext)
@@ -873,6 +897,19 @@
 	if (inode->i_size) {
 		AFFS_INODE->i_blkcnt = last_blk + 1;
 		AFFS_INODE->i_extcnt = ext + 1;
+		if (AFFS_SB->s_flags & SF_OFS) {
+			struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0);
+			u32 tmp;
+			if (IS_ERR(bh)) {
+				affs_warning(sb, "truncate", "unexpected read error for last block %u (%d)",
+					     last_blk, PTR_ERR(bh));
+				return;
+			}
+			tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next);
+			AFFS_DATA_HEAD(bh)->next = 0;
+			affs_adjust_checksum(bh, -tmp);
+			affs_brelse(bh);
+		}
 	} else {
 		AFFS_INODE->i_blkcnt = 0;
 		AFFS_INODE->i_extcnt = 1;
@@ -891,4 +928,5 @@
 		ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
 		affs_brelse(ext_bh);
 	}
+	affs_free_prealloc(inode);
 }
diff -urN linux-2.4.18-pre6/fs/affs/inode.c linux/fs/affs/inode.c
--- linux-2.4.18-pre6/fs/affs/inode.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/affs/inode.c	Wed Jan 23 15:04:33 2002
@@ -68,7 +68,7 @@
 	inode->i_size = 0;
 	inode->i_nlink = 1;
 	inode->i_mode = 0;
-	memset(AFFS_INODE, 0, sizeof(struct affs_inode_info));
+	memset(AFFS_INODE, 0, sizeof(*AFFS_INODE));
 	init_MUTEX(&AFFS_INODE->i_link_lock);
 	init_MUTEX(&AFFS_INODE->i_ext_lock);
 	AFFS_INODE->i_extcnt = 1;
@@ -318,7 +318,7 @@
 	inode->i_ino     = block;
 	inode->i_nlink   = 1;
 	inode->i_mtime   = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-	memset(AFFS_INODE, 0, sizeof(struct affs_inode_info));
+	memset(AFFS_INODE, 0, sizeof(*AFFS_INODE));
 	AFFS_INODE->i_extcnt = 1;
 	AFFS_INODE->i_ext_last = ~1;
 	init_MUTEX(&AFFS_INODE->i_link_lock);
diff -urN linux-2.4.18-pre6/fs/affs/super.c linux/fs/affs/super.c
--- linux-2.4.18-pre6/fs/affs/super.c	Tue Nov 13 09:19:41 2001
+++ linux/fs/affs/super.c	Wed Jan 23 15:04:33 2002
@@ -240,7 +240,7 @@
 
 	sb->s_magic             = AFFS_SUPER_MAGIC;
 	sb->s_op                = &affs_sops;
-	memset(AFFS_SB, 0, sizeof(struct affs_sb_info));
+	memset(AFFS_SB, 0, sizeof(*AFFS_SB));
 	init_MUTEX(&AFFS_SB->s_bmlock);
 
 	if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
@@ -332,7 +332,7 @@
 			       blocksize == 2048 ? 11 : 12;
 
 	/* Find out which kind of FS we have */
-	boot_bh = bread(sb->s_dev, 0, sb->s_blocksize);
+	boot_bh = sb_bread(sb, 0);
 	if (!boot_bh) {
 		printk(KERN_ERR "AFFS: Cannot read boot block\n");
 		goto out_error;
diff -urN linux-2.4.18-pre6/fs/bfs/dir.c linux/fs/bfs/dir.c
--- linux-2.4.18-pre6/fs/bfs/dir.c	Thu Nov 16 13:18:26 2000
+++ linux/fs/bfs/dir.c	Wed Jan 23 15:04:33 2002
@@ -41,7 +41,7 @@
 	while (f->f_pos < dir->i_size) {
 		offset = f->f_pos & (BFS_BSIZE-1);
 		block = dir->iu_sblock + (f->f_pos >> BFS_BSIZE_BITS);
-		bh = bread(dev, block, BFS_BSIZE);
+		bh = sb_bread(dir->i_sb, block);
 		if (!bh) {
 			f->f_pos += BFS_BSIZE - offset;
 			continue;
@@ -270,7 +270,7 @@
 	sblock = dir->iu_sblock;
 	eblock = dir->iu_eblock;
 	for (block=sblock; block<=eblock; block++) {
-		bh = bread(dev, block, BFS_BSIZE);
+		bh = sb_bread(dir->i_sb, block);
 		if(!bh) 
 			return -ENOSPC;
 		for (off=0; off<BFS_BSIZE; off+=BFS_DIRENT_SIZE) {
@@ -319,7 +319,7 @@
 	block = offset = 0;
 	while (block * BFS_BSIZE + offset < dir->i_size) {
 		if (!bh) {
-			bh = bread(dir->i_dev, dir->iu_sblock + block, BFS_BSIZE);
+			bh = sb_bread(dir->i_sb, dir->iu_sblock + block);
 			if (!bh) {
 				block++;
 				continue;
diff -urN linux-2.4.18-pre6/fs/bfs/inode.c linux/fs/bfs/inode.c
--- linux-2.4.18-pre6/fs/bfs/inode.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/bfs/inode.c	Wed Jan 23 15:04:33 2002
@@ -47,7 +47,7 @@
 	}
 
 	block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
-	bh = bread(dev, block, BFS_BSIZE);
+	bh = sb_bread(inode->i_sb, block);
 	if (!bh) {
 		printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino);
 		make_bad_inode(inode);
@@ -100,7 +100,7 @@
 
 	lock_kernel();
 	block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
-	bh = bread(dev, block, BFS_BSIZE);
+	bh = sb_bread(inode->i_sb, block);
 	if (!bh) {
 		printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino);
 		unlock_kernel();
@@ -153,7 +153,7 @@
 	lock_kernel();
 	mark_inode_dirty(inode);
 	block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
-	bh = bread(dev, block, BFS_BSIZE);
+	bh = sb_bread(s, block);
 	if (!bh) {
 		printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino);
 		unlock_kernel();
@@ -252,7 +252,7 @@
 	s->s_blocksize = BFS_BSIZE;
 	s->s_blocksize_bits = BFS_BSIZE_BITS;
 
-	bh = bread(dev, 0, BFS_BSIZE);
+	bh = sb_bread(s, 0);
 	if(!bh)
 		goto out;
 	bfs_sb = (struct bfs_super_block *)bh->b_data;
diff -urN linux-2.4.18-pre6/fs/buffer.c linux/fs/buffer.c
--- linux-2.4.18-pre6/fs/buffer.c	Wed Jan 23 15:04:30 2002
+++ linux/fs/buffer.c	Wed Jan 23 15:04:33 2002
@@ -2096,6 +2096,48 @@
 	goto done;
 }
 
+/*
+ * Commence writeout of all the buffers against a page.  The
+ * page must be locked.   Returns zero on success or a negative
+ * errno.
+ */
+int writeout_one_page(struct page *page)
+{
+	struct buffer_head *bh, *head = page->buffers;
+
+	if (!PageLocked(page))
+		BUG();
+	bh = head;
+	do {
+		if (buffer_locked(bh) || !buffer_dirty(bh) || !buffer_uptodate(bh))
+			continue;
+
+		bh->b_flushtime = jiffies;
+		ll_rw_block(WRITE, 1, &bh);	
+	} while ((bh = bh->b_this_page) != head);
+	return 0;
+}
+EXPORT_SYMBOL(writeout_one_page);
+
+/*
+ * Wait for completion of I/O of all buffers against a page.  The page
+ * must be locked.  Returns zero on success or a negative errno.
+ */
+int waitfor_one_page(struct page *page)
+{
+	int error = 0;
+	struct buffer_head *bh, *head = page->buffers;
+
+	bh = head;
+	do {
+		wait_on_buffer(bh);
+		if (buffer_req(bh) && !buffer_uptodate(bh))
+			error = -EIO;
+	} while ((bh = bh->b_this_page) != head);
+	return error;
+}
+EXPORT_SYMBOL(waitfor_one_page);
+
 int generic_block_bmap(struct address_space *mapping, long block, get_block_t *get_block)
 {
 	struct buffer_head tmp;
diff -urN linux-2.4.18-pre6/fs/cramfs/inode.c linux/fs/cramfs/inode.c
--- linux-2.4.18-pre6/fs/cramfs/inode.c	Fri Dec 21 09:41:55 2001
+++ linux/fs/cramfs/inode.c	Wed Jan 23 15:04:33 2002
@@ -153,7 +153,7 @@
 
 		bh = NULL;
 		if (blocknr + i < devsize) {
-			bh = getblk(sb->s_dev, blocknr + i, PAGE_CACHE_SIZE);
+			bh = sb_getblk(sb, blocknr + i);
 			if (!buffer_uptodate(bh))
 				read_array[unread++] = bh;
 		}
diff -urN linux-2.4.18-pre6/fs/dcache.c linux/fs/dcache.c
--- linux-2.4.18-pre6/fs/dcache.c	Fri Dec 21 09:41:55 2001
+++ linux/fs/dcache.c	Wed Jan 23 15:04:33 2002
@@ -1262,7 +1262,7 @@
 		panic("Cannot create buffer head SLAB cache");
 
 	names_cachep = kmem_cache_create("names_cache", 
-			PATH_MAX + 1, 0, 
+			PATH_MAX, 0, 
 			SLAB_HWCACHE_ALIGN, NULL, NULL);
 	if (!names_cachep)
 		panic("Cannot create names SLAB cache");
diff -urN linux-2.4.18-pre6/fs/efs/dir.c linux/fs/efs/dir.c
--- linux-2.4.18-pre6/fs/efs/dir.c	Fri Nov 17 11:36:27 2000
+++ linux/fs/efs/dir.c	Wed Jan 23 15:04:33 2002
@@ -40,7 +40,7 @@
 	/* look at all blocks */
 	while (block < inode->i_blocks) {
 		/* read the dir block */
-		bh = bread(inode->i_dev, efs_bmap(inode, block), EFS_DIRBSIZE);
+		bh = sb_bread(inode->i_sb, efs_bmap(inode, block));
 
 		if (!bh) {
 			printk(KERN_ERR "EFS: readdir(): failed to read dir block %d\n", block);
diff -urN linux-2.4.18-pre6/fs/efs/inode.c linux/fs/efs/inode.c
--- linux-2.4.18-pre6/fs/efs/inode.c	Sun Sep 30 12:26:08 2001
+++ linux/fs/efs/inode.c	Wed Jan 23 15:04:33 2002
@@ -77,7 +77,7 @@
 			(EFS_BLOCKSIZE / sizeof(struct efs_dinode))) *
 		sizeof(struct efs_dinode);
 
-	bh = bread(inode->i_dev, block, EFS_BLOCKSIZE);
+	bh = sb_bread(inode->i_sb, block);
 	if (!bh) {
 		printk(KERN_WARNING "EFS: bread() failed at block %d\n", block);
 		goto read_inode_error;
@@ -271,7 +271,7 @@
 		if (first || lastblock != iblock) {
 			if (bh) brelse(bh);
 
-			bh = bread(inode->i_dev, iblock, EFS_BLOCKSIZE);
+			bh = sb_bread(inode->i_sb, iblock);
 			if (!bh) {
 				printk(KERN_ERR "EFS: bread() failed at block %d\n", iblock);
 				return 0;
diff -urN linux-2.4.18-pre6/fs/efs/namei.c linux/fs/efs/namei.c
--- linux-2.4.18-pre6/fs/efs/namei.c	Tue Jun  1 23:25:48 1999
+++ linux/fs/efs/namei.c	Wed Jan 23 15:04:33 2002
@@ -24,7 +24,7 @@
 
 	for(block = 0; block < inode->i_blocks; block++) {
 
-		bh = bread(inode->i_dev, efs_bmap(inode, block), EFS_DIRBSIZE);
+		bh = sb_bread(inode->i_sb, efs_bmap(inode, block));
 		if (!bh) {
 			printk(KERN_ERR "EFS: find_entry(): failed to read dir block %d\n", block);
 			return 0;
diff -urN linux-2.4.18-pre6/fs/efs/super.c linux/fs/efs/super.c
--- linux-2.4.18-pre6/fs/efs/super.c	Tue Apr 17 23:16:38 2001
+++ linux/fs/efs/super.c	Wed Jan 23 15:04:33 2002
@@ -137,11 +137,14 @@
 	struct buffer_head *bh;
 
  	sb = SUPER_INFO(s);
-
+ 
+	s->s_magic		= EFS_SUPER_MAGIC;
+	s->s_blocksize		= EFS_BLOCKSIZE;
+	s->s_blocksize_bits	= EFS_BLOCKSIZE_BITS;
 	set_blocksize(dev, EFS_BLOCKSIZE);
   
 	/* read the vh (volume header) block */
-	bh = bread(dev, 0, EFS_BLOCKSIZE);
+	bh = sb_bread(s, 0);
 
 	if (!bh) {
 		printk(KERN_ERR "EFS: cannot read volume header\n");
@@ -160,7 +163,7 @@
 		goto out_no_fs_ul;
 	}
 
-	bh = bread(dev, sb->fs_start + EFS_SUPER, EFS_BLOCKSIZE);
+	bh = sb_bread(s, sb->fs_start + EFS_SUPER);
 	if (!bh) {
 		printk(KERN_ERR "EFS: cannot read superblock\n");
 		goto out_no_fs_ul;
@@ -174,10 +177,6 @@
 		goto out_no_fs_ul;
 	}
 	brelse(bh);
- 
-	s->s_magic		= EFS_SUPER_MAGIC;
-	s->s_blocksize		= EFS_BLOCKSIZE;
-	s->s_blocksize_bits	= EFS_BLOCKSIZE_BITS;
 
 	if (!(s->s_flags & MS_RDONLY)) {
 #ifdef DEBUG
diff -urN linux-2.4.18-pre6/fs/efs/symlink.c linux/fs/efs/symlink.c
--- linux-2.4.18-pre6/fs/efs/symlink.c	Fri Dec 29 14:07:57 2000
+++ linux/fs/efs/symlink.c	Wed Jan 23 15:04:33 2002
@@ -26,13 +26,13 @@
 	lock_kernel();
 	/* read first 512 bytes of link target */
 	err = -EIO;
-	bh = bread(inode->i_dev, efs_bmap(inode, 0), EFS_BLOCKSIZE);
+	bh = sb_bread(inode->i_sb, efs_bmap(inode, 0));
 	if (!bh)
 		goto fail;
 	memcpy(link, bh->b_data, (size > EFS_BLOCKSIZE) ? EFS_BLOCKSIZE : size);
 	brelse(bh);
 	if (size > EFS_BLOCKSIZE) {
-		bh = bread(inode->i_dev, efs_bmap(inode, 1), EFS_BLOCKSIZE);
+		bh = sb_bread(inode->i_sb, efs_bmap(inode, 1));
 		if (!bh)
 			goto fail;
 		memcpy(link + EFS_BLOCKSIZE, bh->b_data, size - EFS_BLOCKSIZE);
diff -urN linux-2.4.18-pre6/fs/ext2/balloc.c linux/fs/ext2/balloc.c
--- linux-2.4.18-pre6/fs/ext2/balloc.c	Fri Oct  5 12:23:53 2001
+++ linux/fs/ext2/balloc.c	Wed Jan 23 15:04:33 2002
@@ -88,7 +88,7 @@
 	if (!gdp)
 		goto error_out;
 	retval = 0;
-	bh = bread (sb->s_dev, le32_to_cpu(gdp->bg_block_bitmap), sb->s_blocksize);
+	bh = sb_bread(sb, le32_to_cpu(gdp->bg_block_bitmap));
 	if (!bh) {
 		ext2_error (sb, "read_block_bitmap",
 			    "Cannot read block bitmap - "
diff -urN linux-2.4.18-pre6/fs/ext2/dir.c linux/fs/ext2/dir.c
--- linux-2.4.18-pre6/fs/ext2/dir.c	Mon Sep 17 13:16:30 2001
+++ linux/fs/ext2/dir.c	Wed Jan 23 15:04:33 2002
@@ -53,8 +53,13 @@
 	int err = 0;
 	dir->i_version = ++event;
 	page->mapping->a_ops->commit_write(NULL, page, from, to);
-	if (IS_SYNC(dir))
-		err = waitfor_one_page(page);
+	if (IS_SYNC(dir)) {
+		int err2;
+		err = writeout_one_page(page);
+		err2 = waitfor_one_page(page);
+		if (err == 0)
+			err = err2;
+	}
 	return err;
 }
 
diff -urN linux-2.4.18-pre6/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c
--- linux-2.4.18-pre6/fs/ext2/ialloc.c	Sun Nov 11 09:59:56 2001
+++ linux/fs/ext2/ialloc.c	Wed Jan 23 15:04:33 2002
@@ -51,8 +51,7 @@
 	if (!desc)
 		goto error_out;
 
-	bh = bread(sb->s_dev, le32_to_cpu(desc->bg_inode_bitmap),
-			sb->s_blocksize);
+	bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap));
 	if (!bh)
 		ext2_error (sb, "read_inode_bitmap",
 			    "Cannot read inode bitmap - "
diff -urN linux-2.4.18-pre6/fs/ext2/inode.c linux/fs/ext2/inode.c
--- linux-2.4.18-pre6/fs/ext2/inode.c	Wed Nov 21 14:07:25 2001
+++ linux/fs/ext2/inode.c	Wed Jan 23 15:04:33 2002
@@ -239,8 +239,7 @@
 				 Indirect chain[4],
 				 int *err)
 {
-	kdev_t dev = inode->i_dev;
-	int size = inode->i_sb->s_blocksize;
+	struct super_block *sb = inode->i_sb;
 	Indirect *p = chain;
 	struct buffer_head *bh;
 
@@ -250,7 +249,7 @@
 	if (!p->key)
 		goto no_block;
 	while (--depth) {
-		bh = bread(dev, le32_to_cpu(p->key), size);
+		bh = sb_bread(sb, le32_to_cpu(p->key));
 		if (!bh)
 			goto failure;
 		/* Reader: pointers */
@@ -399,7 +398,7 @@
 		 * Get buffer_head for parent block, zero it out and set 
 		 * the pointer to new one, then send parent to disk.
 		 */
-		bh = getblk(inode->i_dev, parent, blocksize);
+		bh = sb_getblk(inode->i_sb, parent);
 		lock_buffer(bh);
 		memset(bh->b_data, 0, blocksize);
 		branch[n].bh = bh;
@@ -763,7 +762,7 @@
 			if (!nr)
 				continue;
 			*p = 0;
-			bh = bread (inode->i_dev, nr, inode->i_sb->s_blocksize);
+			bh = sb_bread(inode->i_sb, nr);
 			/*
 			 * A read failure? Report error and clear slot
 			 * (should be rare).
@@ -921,7 +920,7 @@
 		EXT2_INODE_SIZE(inode->i_sb);
 	block = le32_to_cpu(gdp[desc].bg_inode_table) +
 		(offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb));
-	if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) {
+	if (!(bh = sb_bread(inode->i_sb, block))) {
 		ext2_error (inode->i_sb, "ext2_read_inode",
 			    "unable to read inode block - "
 			    "inode=%lu, block=%lu", inode->i_ino, block);
@@ -1063,7 +1062,7 @@
 		EXT2_INODE_SIZE(inode->i_sb);
 	block = le32_to_cpu(gdp[desc].bg_inode_table) +
 		(offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb));
-	if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) {
+	if (!(bh = sb_bread(inode->i_sb, block))) {
 		ext2_error (inode->i_sb, "ext2_write_inode",
 			    "unable to read inode block - "
 			    "inode=%lu, block=%lu", inode->i_ino, block);
diff -urN linux-2.4.18-pre6/fs/ext2/super.c linux/fs/ext2/super.c
--- linux-2.4.18-pre6/fs/ext2/super.c	Fri Dec 21 09:41:55 2001
+++ linux/fs/ext2/super.c	Wed Jan 23 15:04:33 2002
@@ -433,6 +433,7 @@
 		printk ("EXT2-fs: unable to set blocksize %d\n", blocksize);
 		return NULL;
 	}
+	sb->s_blocksize = blocksize;
 
 	/*
 	 * If the superblock doesn't start on a sector boundary,
@@ -444,7 +445,7 @@
 		offset = (sb_block*BLOCK_SIZE) % blocksize;
 	}
 
-	if (!(bh = bread (dev, logic_sb_block, blocksize))) {
+	if (!(bh = sb_bread(sb, logic_sb_block))) {
 		printk ("EXT2-fs: unable to read superblock\n");
 		return NULL;
 	}
@@ -503,7 +504,7 @@
 
 		logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize;
 		offset = (sb_block*BLOCK_SIZE) % blocksize;
-		bh = bread (dev, logic_sb_block, blocksize);
+		bh = sb_bread(sb, logic_sb_block);
 		if(!bh) {
 			printk("EXT2-fs: Couldn't read superblock on "
 			       "2nd try.\n");
@@ -607,8 +608,7 @@
 		goto failed_mount;
 	}
 	for (i = 0; i < db_count; i++) {
-		sb->u.ext2_sb.s_group_desc[i] = bread (dev, logic_sb_block + i + 1,
-						       sb->s_blocksize);
+		sb->u.ext2_sb.s_group_desc[i] = sb_bread(sb, logic_sb_block + i + 1);
 		if (!sb->u.ext2_sb.s_group_desc[i]) {
 			for (j = 0; j < i; j++)
 				brelse (sb->u.ext2_sb.s_group_desc[j]);
diff -urN linux-2.4.18-pre6/fs/ext3/balloc.c linux/fs/ext3/balloc.c
--- linux-2.4.18-pre6/fs/ext3/balloc.c	Fri Nov  9 14:25:04 2001
+++ linux/fs/ext3/balloc.c	Wed Jan 23 15:04:33 2002
@@ -91,8 +91,7 @@
 	if (!gdp)
 		goto error_out;
 	retval = 0;
-	bh = bread (sb->s_dev,
-			le32_to_cpu(gdp->bg_block_bitmap), sb->s_blocksize);
+	bh = sb_bread(sb, le32_to_cpu(gdp->bg_block_bitmap));
 	if (!bh) {
 		ext3_error (sb, "read_block_bitmap",
 			    "Cannot read block bitmap - "
@@ -353,8 +352,7 @@
 #ifdef CONFIG_JBD_DEBUG
 		{
 			struct buffer_head *debug_bh;
-			debug_bh = get_hash_table(sb->s_dev, block + i,
-							sb->s_blocksize);
+			debug_bh = sb_get_hash_table(sb, block + i);
 			if (debug_bh) {
 				BUFFER_TRACE(debug_bh, "Deleted!");
 				if (!bh2jh(bitmap_bh)->b_committed_data)
@@ -702,7 +700,7 @@
 		struct buffer_head *debug_bh;
 
 		/* Record bitmap buffer state in the newly allocated block */
-		debug_bh = get_hash_table(sb->s_dev, tmp, sb->s_blocksize);
+		debug_bh = sb_get_hash_table(sb, tmp);
 		if (debug_bh) {
 			BUFFER_TRACE(debug_bh, "state when allocated");
 			BUFFER_TRACE2(debug_bh, bh, "bitmap state");
diff -urN linux-2.4.18-pre6/fs/ext3/ialloc.c linux/fs/ext3/ialloc.c
--- linux-2.4.18-pre6/fs/ext3/ialloc.c	Wed Jan 23 15:04:30 2002
+++ linux/fs/ext3/ialloc.c	Wed Jan 23 15:04:33 2002
@@ -60,8 +60,7 @@
 		retval = -EIO;
 		goto error_out;
 	}
-	bh = bread (sb->s_dev,
-			le32_to_cpu(gdp->bg_inode_bitmap), sb->s_blocksize);
+	bh = sb_bread(sb, le32_to_cpu(gdp->bg_inode_bitmap));
 	if (!bh) {
 		ext3_error (sb, "read_inode_bitmap",
 			    "Cannot read inode bitmap - "
diff -urN linux-2.4.18-pre6/fs/ext3/inode.c linux/fs/ext3/inode.c
--- linux-2.4.18-pre6/fs/ext3/inode.c	Fri Dec 21 09:41:55 2001
+++ linux/fs/ext3/inode.c	Wed Jan 23 15:04:33 2002
@@ -388,8 +388,7 @@
 static Indirect *ext3_get_branch(struct inode *inode, int depth, int *offsets,
 				 Indirect chain[4], int *err)
 {
-	kdev_t dev = inode->i_dev;
-	int blocksize = inode->i_sb->s_blocksize;
+	struct super_block *sb = inode->i_sb;
 	Indirect *p = chain;
 	struct buffer_head *bh;
 
@@ -399,7 +398,7 @@
 	if (!p->key)
 		goto no_block;
 	while (--depth) {
-		bh = bread(dev, le32_to_cpu(p->key), blocksize);
+		bh = sb_bread(sb, le32_to_cpu(p->key));
 		if (!bh)
 			goto failure;
 		/* Reader: pointers */
@@ -557,7 +556,7 @@
 			 * and set the pointer to new one, then send
 			 * parent to disk.  
 			 */
-			bh = getblk(inode->i_dev, parent, blocksize);
+			bh = sb_getblk(inode->i_sb, parent);
 			branch[n].bh = bh;
 			lock_buffer(bh);
 			BUFFER_TRACE(bh, "call get_create_access");
@@ -858,8 +857,7 @@
 	*errp = ext3_get_block_handle(handle, inode, block, &dummy, create);
 	if (!*errp && buffer_mapped(&dummy)) {
 		struct buffer_head *bh;
-		bh = getblk(dummy.b_dev, dummy.b_blocknr,
-					inode->i_sb->s_blocksize);
+		bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
 		if (buffer_new(&dummy)) {
 			J_ASSERT(create != 0);
 			J_ASSERT(handle != 0);
@@ -1576,9 +1574,6 @@
 		u32 *first, u32 *last)
 {
 	u32 *p;
-	kdev_t dev = inode->i_sb->s_dev;
-	unsigned long blocksize = inode->i_sb->s_blocksize;
-
 	if (try_to_extend_transaction(handle, inode)) {
 		if (bh) {
 			BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
@@ -1604,7 +1599,7 @@
 			struct buffer_head *bh;
 
 			*p = 0;
-			bh = get_hash_table(dev, nr, blocksize);
+			bh = sb_get_hash_table(inode->i_sb, nr);
 			ext3_forget(handle, 0, inode, bh, nr);
 		}
 	}
@@ -1717,7 +1712,7 @@
 				continue;		/* A hole */
 
 			/* Go read the buffer for the next level down */
-			bh = bread(inode->i_dev, nr, inode->i_sb->s_blocksize);
+			bh = sb_bread(inode->i_sb, nr);
 
 			/*
 			 * A read failure? Report error and clear slot
@@ -2030,7 +2025,7 @@
 		EXT3_INODE_SIZE(inode->i_sb);
 	block = le32_to_cpu(gdp[desc].bg_inode_table) +
 		(offset >> EXT3_BLOCK_SIZE_BITS(inode->i_sb));
-	if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) {
+	if (!(bh = sb_bread(inode->i_sb, block))) {
 		ext3_error (inode->i_sb, "ext3_get_inode_loc",
 			    "unable to read inode block - "
 			    "inode=%lu, block=%lu", inode->i_ino, block);
diff -urN linux-2.4.18-pre6/fs/ext3/super.c linux/fs/ext3/super.c
--- linux-2.4.18-pre6/fs/ext3/super.c	Wed Jan 23 15:04:30 2002
+++ linux/fs/ext3/super.c	Wed Jan 23 15:04:33 2002
@@ -926,6 +926,7 @@
 		goto out_fail;
 	}
 
+	sb->s_blocksize = blocksize;
 	set_blocksize (dev, blocksize);
 
 	/*
@@ -937,7 +938,7 @@
 		offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize;
 	}
 
-	if (!(bh = bread (dev, logic_sb_block, blocksize))) {
+	if (!(bh = sb_bread(sb, logic_sb_block))) {
 		printk (KERN_ERR "EXT3-fs: unable to read superblock\n");
 		goto out_fail;
 	}
@@ -1010,7 +1011,7 @@
 		set_blocksize (dev, sb->s_blocksize);
 		logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize;
 		offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize;
-		bh = bread (dev, logic_sb_block, blocksize);
+		bh = sb_bread(sb, logic_sb_block);
 		if (!bh) {
 			printk(KERN_ERR 
 			       "EXT3-fs: Can't read superblock on 2nd try.\n");
@@ -1094,8 +1095,7 @@
 		goto failed_mount;
 	}
 	for (i = 0; i < db_count; i++) {
-		sbi->s_group_desc[i] = bread(dev, logic_sb_block + i + 1,
-					     blocksize);
+		sbi->s_group_desc[i] = sb_bread(sb, logic_sb_block + i + 1);
 		if (!sbi->s_group_desc[i]) {
 			printk (KERN_ERR "EXT3-fs: "
 				"can't read group descriptor %d\n", i);
diff -urN linux-2.4.18-pre6/fs/fat/buffer.c linux/fs/fat/buffer.c
--- linux-2.4.18-pre6/fs/fat/buffer.c	Tue Jul 24 14:23:53 2001
+++ linux/fs/fat/buffer.c	Wed Jan 23 15:04:33 2002
@@ -59,12 +59,12 @@
 
 struct buffer_head *default_fat_bread(struct super_block *sb, int block)
 {
-	return bread (sb->s_dev, block, sb->s_blocksize);
+	return sb_bread(sb, block);
 }
 
 struct buffer_head *default_fat_getblk(struct super_block *sb, int block)
 {
-	return getblk (sb->s_dev, block, sb->s_blocksize);
+	return sb_getblk(sb, block);
 }
 
 void default_fat_brelse(struct super_block *sb, struct buffer_head *bh)
diff -urN linux-2.4.18-pre6/fs/fat/inode.c linux/fs/fat/inode.c
--- linux-2.4.18-pre6/fs/fat/inode.c	Wed Jan 23 15:04:30 2002
+++ linux/fs/fat/inode.c	Wed Jan 23 15:04:33 2002
@@ -584,7 +584,7 @@
 
 	sb->s_blocksize = hard_blksize;
 	set_blocksize(sb->s_dev, hard_blksize);
-	bh = bread(sb->s_dev, 0, sb->s_blocksize);
+	bh = sb_bread(sb, 0);
 	if (bh == NULL) {
 		printk("FAT: unable to read boot sector\n");
 		goto out_fail;
@@ -656,7 +656,7 @@
 			(sbi->fsinfo_sector * logical_sector_size) % hard_blksize;
 		fsinfo_bh = bh;
 		if (fsinfo_block != 0) {
-			fsinfo_bh = bread(sb->s_dev, fsinfo_block, hard_blksize);
+			fsinfo_bh = sb_bread(sb, fsinfo_block);
 			if (fsinfo_bh == NULL) {
 				printk("FAT: bread failed, FSINFO block"
 				       " (blocknr = %d)\n", fsinfo_block);
diff -urN linux-2.4.18-pre6/fs/freevxfs/vxfs_bmap.c linux/fs/freevxfs/vxfs_bmap.c
--- linux-2.4.18-pre6/fs/freevxfs/vxfs_bmap.c	Sun Sep  2 10:34:36 2001
+++ linux/fs/freevxfs/vxfs_bmap.c	Wed Jan 23 15:04:33 2002
@@ -137,9 +137,8 @@
 		struct vxfs_typed	*typ;
 		int64_t			off;
 
-		bp = bread(ip->i_dev,
-				indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb)),
-				ip->i_sb->s_blocksize);
+		bp = sb_bread(ip->i_sb,
+				indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb)));
 		if (!buffer_mapped(bp))
 			return 0;
 
diff -urN linux-2.4.18-pre6/fs/freevxfs/vxfs_inode.c linux/fs/freevxfs/vxfs_inode.c
--- linux-2.4.18-pre6/fs/freevxfs/vxfs_inode.c	Sun Sep  2 10:34:36 2001
+++ linux/fs/freevxfs/vxfs_inode.c	Wed Jan 23 15:04:33 2002
@@ -104,7 +104,7 @@
 
 	block = extent + ((ino * VXFS_ISIZE) / sbp->s_blocksize);
 	offset = ((ino % (sbp->s_blocksize / VXFS_ISIZE)) * VXFS_ISIZE);
-	bp = bread(sbp->s_dev, block, sbp->s_blocksize);
+	bp = sb_bread(sbp, block);
 
 	if (buffer_mapped(bp)) {
 		struct vxfs_inode_info	*vip;
diff -urN linux-2.4.18-pre6/fs/freevxfs/vxfs_subr.c linux/fs/freevxfs/vxfs_subr.c
--- linux-2.4.18-pre6/fs/freevxfs/vxfs_subr.c	Fri Nov  9 14:25:35 2001
+++ linux/fs/freevxfs/vxfs_subr.c	Wed Jan 23 15:04:33 2002
@@ -114,7 +114,7 @@
 	daddr_t			pblock;
 
 	pblock = vxfs_bmap1(ip, block);
-	bp = bread(ip->i_dev, pblock, ip->i_sb->s_blocksize);
+	bp = sb_bread(ip->i_sb, pblock);
 
 	return (bp);
 }
diff -urN linux-2.4.18-pre6/fs/hfs/file.c linux/fs/hfs/file.c
--- linux-2.4.18-pre6/fs/hfs/file.c	Sun Aug 12 10:56:56 2001
+++ linux/fs/hfs/file.c	Wed Jan 23 15:04:33 2002
@@ -61,7 +61,7 @@
 struct buffer_head *hfs_getblk(struct hfs_fork *fork, int block, int create)
 {
 	int tmp;
-	kdev_t dev = fork->entry->mdb->sys_mdb->s_dev;
+	struct super_block *sb = fork->entry->mdb->sys_mdb;
 
 	tmp = hfs_extent_map(fork, block, create);
 
@@ -71,7 +71,7 @@
 		*/
 		if (tmp) {
 			hfs_cat_mark_dirty(fork->entry);
-			return getblk(dev, tmp, HFS_SECTOR_SIZE);
+			return sb_getblk(sb, tmp);
 		}
 		return NULL;
 	} else {
@@ -80,8 +80,7 @@
 		   we waited on the I/O in getblk to complete.
 		*/
 		do {
-			struct buffer_head *bh =
-					getblk(dev, tmp, HFS_SECTOR_SIZE);
+			struct buffer_head *bh = sb_getblk(sb, tmp);
 			int tmp2 = hfs_extent_map(fork, block, 0);
 
 			if (tmp2 == tmp) {
diff -urN linux-2.4.18-pre6/fs/hfs/super.c linux/fs/hfs/super.c
--- linux-2.4.18-pre6/fs/hfs/super.c	Thu Oct 25 00:02:26 2001
+++ linux/fs/hfs/super.c	Wed Jan 23 15:04:33 2002
@@ -402,6 +402,8 @@
 
 	/* set the device driver to 512-byte blocks */
 	set_blocksize(dev, HFS_SECTOR_SIZE);
+	s->s_blocksize_bits = HFS_SECTOR_SIZE_BITS;
+	s->s_blocksize = HFS_SECTOR_SIZE;
 
 #ifdef CONFIG_MAC_PARTITION
 	/* check to see if we're in a partition */
@@ -437,8 +439,6 @@
 	}
 
 	s->s_magic = HFS_SUPER_MAGIC;
-	s->s_blocksize_bits = HFS_SECTOR_SIZE_BITS;
-	s->s_blocksize = HFS_SECTOR_SIZE;
 	s->s_op = &hfs_super_operations;
 
 	/* try to get the root inode */
diff -urN linux-2.4.18-pre6/fs/hfs/sysdep.c linux/fs/hfs/sysdep.c
--- linux-2.4.18-pre6/fs/hfs/sysdep.c	Tue Feb 13 14:13:45 2001
+++ linux/fs/hfs/sysdep.c	Wed Jan 23 15:04:33 2002
@@ -41,9 +41,9 @@
 	hfs_buffer tmp = HFS_BAD_BUFFER;
 
 	if (read) {
-		tmp = bread(sys_mdb->s_dev, block, HFS_SECTOR_SIZE);
+		tmp = sb_bread(sys_mdb, block);
 	} else {
-		tmp = getblk(sys_mdb->s_dev, block, HFS_SECTOR_SIZE);
+		tmp = sb_getblk(sys_mdb, block);
 		if (tmp) {
 			mark_buffer_uptodate(tmp, 1);
 		}
diff -urN linux-2.4.18-pre6/fs/hpfs/buffer.c linux/fs/hpfs/buffer.c
--- linux-2.4.18-pre6/fs/hpfs/buffer.c	Sat Dec  9 11:43:03 2000
+++ linux/fs/hpfs/buffer.c	Wed Jan 23 15:04:33 2002
@@ -122,12 +122,9 @@
 void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head **bhp,
 		 int ahead)
 {
-	kdev_t dev = s->s_dev;
 	struct buffer_head *bh;
 
-	if (!ahead || secno + ahead >= s->s_hpfs_fs_size)
-		*bhp = bh = bread(dev, secno, 512);
-	else *bhp = bh = bread(dev, secno, 512);
+	*bhp = bh = sb_bread(s, secno);
 	if (bh != NULL)
 		return bh->b_data;
 	else {
@@ -143,7 +140,7 @@
 	struct buffer_head *bh;
 	/*return hpfs_map_sector(s, secno, bhp, 0);*/
 
-	if ((*bhp = bh = getblk(s->s_dev, secno, 512)) != NULL) {
+	if ((*bhp = bh = sb_getblk(s, secno)) != NULL) {
 		if (!buffer_uptodate(bh)) wait_on_buffer(bh);
 		mark_buffer_uptodate(bh, 1);
 		return bh->b_data;
@@ -158,7 +155,6 @@
 void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffer_head *qbh,
 		   int ahead)
 {
-	kdev_t dev = s->s_dev;
 	struct buffer_head *bh;
 	char *data;
 
@@ -173,24 +169,22 @@
 		goto bail;
 	}
 
-	if (!ahead || secno + 4 + ahead > s->s_hpfs_fs_size)
-		qbh->bh[0] = bh = bread(dev, secno, 512);
-	else qbh->bh[0] = bh = bread(dev, secno, 512);
+	qbh->bh[0] = bh = sb_bread(s, secno);
 	if (!bh)
 		goto bail0;
 	memcpy(data, bh->b_data, 512);
 
-	qbh->bh[1] = bh = bread(dev, secno + 1, 512);
+	qbh->bh[1] = bh = sb_bread(s, secno + 1);
 	if (!bh)
 		goto bail1;
 	memcpy(data + 512, bh->b_data, 512);
 
-	qbh->bh[2] = bh = bread(dev, secno + 2, 512);
+	qbh->bh[2] = bh = sb_bread(s, secno + 2);
 	if (!bh)
 		goto bail2;
 	memcpy(data + 2 * 512, bh->b_data, 512);
 
-	qbh->bh[3] = bh = bread(dev, secno + 3, 512);
+	qbh->bh[3] = bh = sb_bread(s, secno + 3);
 	if (!bh)
 		goto bail3;
 	memcpy(data + 3 * 512, bh->b_data, 512);
diff -urN linux-2.4.18-pre6/fs/isofs/dir.c linux/fs/isofs/dir.c
--- linux-2.4.18-pre6/fs/isofs/dir.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/isofs/dir.c	Wed Jan 23 15:04:33 2002
@@ -123,7 +123,7 @@
 		int de_len;
 
 		if (!bh) {
-			bh = isofs_bread(inode, bufsize, block);
+			bh = isofs_bread(inode, block);
 			if (!bh)
 				return 0;
 		}
@@ -158,7 +158,7 @@
 			brelse(bh);
 			bh = NULL;
 			if (offset) {
-				bh = isofs_bread(inode, bufsize, block);
+				bh = isofs_bread(inode, block);
 				if (!bh)
 					return 0;
 				memcpy((void *) tmpde + slop, bh->b_data, offset);
diff -urN linux-2.4.18-pre6/fs/isofs/inode.c linux/fs/isofs/inode.c
--- linux-2.4.18-pre6/fs/isofs/inode.c	Thu Oct 25 13:53:53 2001
+++ linux/fs/isofs/inode.c	Wed Jan 23 15:04:33 2002
@@ -527,6 +527,7 @@
 	}
 
 	set_blocksize(dev, opt.blocksize);
+	s->s_blocksize = opt.blocksize;
 
 	s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */
 
@@ -540,8 +541,8 @@
 	    struct iso_volume_descriptor  * vdp;
 
 	    block = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits);
-	    if (!(bh = bread(dev, block, opt.blocksize)))
-		goto out_no_read;		
+	    if (!(bh = sb_bread(s, block)))
+		goto out_no_read;
 
 	    vdp = (struct iso_volume_descriptor *)bh->b_data;
 	    hdp = (struct hs_volume_descriptor *)bh->b_data;
@@ -896,7 +897,6 @@
 	unsigned int firstext;
 	unsigned long nextino;
 	int section, rv;
-	unsigned int blocksize = inode->i_sb->s_blocksize;
 
 	lock_kernel();
 
@@ -957,7 +957,7 @@
 			(*bh_result)->b_blocknr  = firstext + b_off - offset;
 			(*bh_result)->b_state   |= (1UL << BH_Mapped);
 		} else {
-			*bh_result = getblk(inode->i_dev, firstext+b_off-offset, blocksize);
+			*bh_result = sb_getblk(inode->i_sb, firstext+b_off-offset);
 			if ( !*bh_result )
 				goto abort;
 		}
@@ -1000,12 +1000,12 @@
 	return 0;
 }
 
-struct buffer_head *isofs_bread(struct inode *inode, unsigned int bufsize, unsigned int block)
+struct buffer_head *isofs_bread(struct inode *inode, unsigned int block)
 {
 	unsigned int blknr = isofs_bmap(inode, block);
 	if (!blknr)
 		return NULL;
-	return bread(inode->i_dev, blknr, bufsize);
+	return sb_bread(inode->i_sb, blknr);
 }
 
 static int isofs_readpage(struct file *file, struct page *page)
@@ -1060,7 +1060,7 @@
 		unsigned int de_len;
 
 		if (!bh) {
-			bh = bread(inode->i_dev, block, bufsize);
+			bh = sb_bread(inode->i_sb, block);
 			if (!bh)
 				goto out_noread;
 		}
@@ -1092,7 +1092,7 @@
 			brelse(bh);
 			bh = NULL;
 			if (offset) {
-				bh = bread(inode->i_dev, block, bufsize);
+				bh = sb_bread(inode->i_sb, block);
 				if (!bh)
 					goto out_noread;
 				memcpy((void *) tmpde + slop, bh->b_data, offset);
@@ -1150,7 +1150,7 @@
 	unsigned long offset;
 	int volume_seq_no, i;
 
-	bh = bread(inode->i_dev, block, bufsize);
+	bh = sb_bread(inode->i_sb, block);
 	if (!bh)
 		goto out_badread;
 
@@ -1168,7 +1168,7 @@
 		}
 		memcpy(tmpde, bh->b_data + offset, frag1);
 		brelse(bh);
-		bh = bread(inode->i_dev, ++block, bufsize);
+		bh = sb_bread(inode->i_sb, ++block);
 		if (!bh)
 			goto out_badread;
 		memcpy((char *)tmpde+frag1, bh->b_data, de_len - frag1);
@@ -1345,7 +1345,7 @@
 #ifdef LEAK_CHECK
 #undef malloc
 #undef free_s
-#undef bread
+#undef sb_bread
 #undef brelse
 
 void * leak_check_malloc(unsigned int size){
@@ -1360,9 +1360,9 @@
   return kfree(obj);
 }
 
-struct buffer_head * leak_check_bread(int dev, int block, int size){
+struct buffer_head * leak_check_bread(struct super_block *sb, int block){
   check_bread++;
-  return bread(dev, block, size);
+  return sb_bread(sb, block);
 }
 
 void leak_check_brelse(struct buffer_head * bh){
diff -urN linux-2.4.18-pre6/fs/isofs/namei.c linux/fs/isofs/namei.c
--- linux-2.4.18-pre6/fs/isofs/namei.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/isofs/namei.c	Wed Jan 23 15:04:33 2002
@@ -78,7 +78,7 @@
 		char *dpnt;
 
 		if (!bh) {
-			bh = isofs_bread(dir, bufsize, block);
+			bh = isofs_bread(dir, block);
 			if (!bh)
 				return 0;
 		}
@@ -108,7 +108,7 @@
 			brelse(bh);
 			bh = NULL;
 			if (offset) {
-				bh = isofs_bread(dir, bufsize, block);
+				bh = isofs_bread(dir, block);
 				if (!bh)
 					return 0;
 				memcpy((void *) tmpde + slop, bh->b_data, offset);
diff -urN linux-2.4.18-pre6/fs/isofs/rock.c linux/fs/isofs/rock.c
--- linux-2.4.18-pre6/fs/isofs/rock.c	Thu Oct 25 13:53:53 2001
+++ linux/fs/isofs/rock.c	Wed Jan 23 15:04:33 2002
@@ -69,7 +69,7 @@
     block = cont_extent; \
     offset = cont_offset; \
     offset1 = 0; \
-    pbh = bread(DEV->i_dev, block, ISOFS_BUFFER_SIZE(DEV)); \
+    pbh = sb_bread(DEV->i_sb, block); \
     if(pbh){       \
       memcpy(buffer + offset1, pbh->b_data + offset, cont_size - offset1); \
       brelse(pbh); \
@@ -511,7 +511,7 @@
 
 	block = inode->i_ino >> bufbits;
 	lock_kernel();
-	bh = bread(inode->i_dev, block, bufsize);
+	bh = sb_bread(inode->i_sb, block);
 	if (!bh)
 		goto out_noread;
 
diff -urN linux-2.4.18-pre6/fs/minix/bitmap.c linux/fs/minix/bitmap.c
--- linux-2.4.18-pre6/fs/minix/bitmap.c	Fri Sep  7 09:45:51 2001
+++ linux/fs/minix/bitmap.c	Wed Jan 23 15:04:33 2002
@@ -133,7 +133,7 @@
 	ino--;
 	block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks +
 		 ino / MINIX_INODES_PER_BLOCK;
-	*bh = bread(sb->s_dev, block, BLOCK_SIZE);
+	*bh = sb_bread(sb, block);
 	if (!*bh) {
 		printk("unable to read i-node block\n");
 		return NULL;
@@ -158,7 +158,7 @@
 	ino--;
 	block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks +
 		 ino / MINIX2_INODES_PER_BLOCK;
-	*bh = bread(sb->s_dev, block, BLOCK_SIZE);
+	*bh = sb_bread(sb, block);
 	if (!*bh) {
 		printk("unable to read i-node block\n");
 		return NULL;
diff -urN linux-2.4.18-pre6/fs/minix/dir.c linux/fs/minix/dir.c
--- linux-2.4.18-pre6/fs/minix/dir.c	Fri Sep  7 09:45:51 2001
+++ linux/fs/minix/dir.c	Wed Jan 23 15:04:33 2002
@@ -36,8 +36,13 @@
 	struct inode *dir = (struct inode *)page->mapping->host;
 	int err = 0;
 	page->mapping->a_ops->commit_write(NULL, page, from, to);
-	if (IS_SYNC(dir))
-		err = waitfor_one_page(page);
+	if (IS_SYNC(dir)) {
+		int err2;
+		err = writeout_one_page(page);
+		err2 = waitfor_one_page(page);
+		if (err == 0)
+			err = err2;
+	}
 	return err;
 }
 
@@ -236,10 +241,10 @@
 
 	lock_page(page);
 	err = mapping->a_ops->prepare_write(NULL, page, from, to);
-	if (err)
-		BUG();
-	de->inode = 0;
-	err = dir_commit_chunk(page, from, to);
+	if (err == 0) {
+		de->inode = 0;
+		err = dir_commit_chunk(page, from, to);
+	}
 	UnlockPage(page);
 	dir_put_page(page);
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
@@ -336,10 +341,10 @@
 
 	lock_page(page);
 	err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
-	if (err)
-		BUG();
-	de->inode = inode->i_ino;
-	err = dir_commit_chunk(page, from, to);
+	if (err == 0) {
+		de->inode = inode->i_ino;
+		err = dir_commit_chunk(page, from, to);
+	}
 	UnlockPage(page);
 	dir_put_page(page);
 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
diff -urN linux-2.4.18-pre6/fs/minix/inode.c linux/fs/minix/inode.c
--- linux-2.4.18-pre6/fs/minix/inode.c	Wed Jan 23 15:04:30 2002
+++ linux/fs/minix/inode.c	Wed Jan 23 15:04:33 2002
@@ -143,15 +143,15 @@
 		goto out_bad_hblock;
 
 	set_blocksize(dev, BLOCK_SIZE);
-	if (!(bh = bread(dev,1,BLOCK_SIZE)))
+	s->s_blocksize = BLOCK_SIZE;
+	s->s_blocksize_bits = BLOCK_SIZE_BITS;
+	if (!(bh = sb_bread(s, 1)))
 		goto out_bad_sb;
 
 	ms = (struct minix_super_block *) bh->b_data;
 	sbi->s_ms = ms;
 	sbi->s_sbh = bh;
 	sbi->s_mount_state = ms->s_state;
-	s->s_blocksize = BLOCK_SIZE;
-	s->s_blocksize_bits = BLOCK_SIZE_BITS;
 	sbi->s_ninodes = ms->s_ninodes;
 	sbi->s_nzones = ms->s_nzones;
 	sbi->s_imap_blocks = ms->s_imap_blocks;
@@ -198,12 +198,12 @@
 
 	block=2;
 	for (i=0 ; i < sbi->s_imap_blocks ; i++) {
-		if (!(sbi->s_imap[i]=bread(dev,block,BLOCK_SIZE)))
+		if (!(sbi->s_imap[i]=sb_bread(s, block)))
 			goto out_no_bitmap;
 		block++;
 	}
 	for (i=0 ; i < sbi->s_zmap_blocks ; i++) {
-		if (!(sbi->s_zmap[i]=bread(dev,block,BLOCK_SIZE)))
+		if (!(sbi->s_zmap[i]=sb_bread(s, block)))
 			goto out_no_bitmap;
 		block++;
 	}
diff -urN linux-2.4.18-pre6/fs/minix/itree_common.c linux/fs/minix/itree_common.c
--- linux-2.4.18-pre6/fs/minix/itree_common.c	Fri Sep  7 09:45:51 2001
+++ linux/fs/minix/itree_common.c	Wed Jan 23 15:04:33 2002
@@ -30,7 +30,7 @@
 					Indirect chain[DEPTH],
 					int *err)
 {
-	kdev_t dev = inode->i_dev;
+	struct super_block *sb = inode->i_sb;
 	Indirect *p = chain;
 	struct buffer_head *bh;
 
@@ -40,7 +40,7 @@
 	if (!p->key)
 		goto no_block;
 	while (--depth) {
-		bh = bread(dev, block_to_cpu(p->key), BLOCK_SIZE);
+		bh = sb_bread(sb, block_to_cpu(p->key));
 		if (!bh)
 			goto failure;
 		/* Reader: pointers */
@@ -79,7 +79,7 @@
 		if (!nr)
 			break;
 		branch[n].key = cpu_to_block(nr);
-		bh = getblk(inode->i_dev, parent, BLOCK_SIZE);
+		bh = sb_getblk(inode->i_sb, parent);
 		lock_buffer(bh);
 		memset(bh->b_data, 0, BLOCK_SIZE);
 		branch[n].bh = bh;
@@ -277,7 +277,7 @@
 			if (!nr)
 				continue;
 			*p = 0;
-			bh = bread (inode->i_dev, nr, BLOCK_SIZE);
+			bh = sb_bread(inode->i_sb, nr);
 			if (!bh)
 				continue;
 			free_branches(inode, (block_t*)bh->b_data,
diff -urN linux-2.4.18-pre6/fs/namei.c linux/fs/namei.c
--- linux-2.4.18-pre6/fs/namei.c	Wed Oct 17 14:46:29 2001
+++ linux/fs/namei.c	Wed Jan 23 15:04:33 2002
@@ -99,16 +99,17 @@
  * kernel data space before using them..
  *
  * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
+ * PATH_MAX includes the nul terminator --RR.
  */
 static inline int do_getname(const char *filename, char *page)
 {
 	int retval;
-	unsigned long len = PATH_MAX + 1;
+	unsigned long len = PATH_MAX;
 
 	if ((unsigned long) filename >= TASK_SIZE) {
 		if (!segment_eq(get_fs(), KERNEL_DS))
 			return -EFAULT;
-	} else if (TASK_SIZE - (unsigned long) filename < PATH_MAX + 1)
+	} else if (TASK_SIZE - (unsigned long) filename < PATH_MAX)
 		len = TASK_SIZE - (unsigned long) filename;
 
 	retval = strncpy_from_user((char *)page, filename, len);
diff -urN linux-2.4.18-pre6/fs/namespace.c linux/fs/namespace.c
--- linux-2.4.18-pre6/fs/namespace.c	Fri Dec 21 09:41:55 2001
+++ linux/fs/namespace.c	Wed Jan 23 15:04:33 2002
@@ -563,6 +563,67 @@
 	return err;
 }
 
+static int do_move_mount(struct nameidata *nd, char *old_name)
+{
+	struct nameidata old_nd, parent_nd;
+	struct vfsmount *p;
+	int err = 0;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!old_name || !*old_name)
+		return -EINVAL;
+	if (path_init(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd))
+		err = path_walk(old_name, &old_nd);
+	if (err)
+		return err;
+
+	down(&mount_sem);
+	while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
+		;
+	err = -EINVAL;
+	if (!check_mnt(nd->mnt) || !check_mnt(old_nd.mnt))
+		goto out;
+
+	err = -ENOENT;
+	down(&nd->dentry->d_inode->i_zombie);
+	if (IS_DEADDIR(nd->dentry->d_inode))
+		goto out1;
+
+	spin_lock(&dcache_lock);
+	if (!IS_ROOT(nd->dentry) && d_unhashed(nd->dentry))
+		goto out2;
+
+	err = -EINVAL;
+	if (old_nd.dentry != old_nd.mnt->mnt_root)
+		goto out2;
+
+	if (old_nd.mnt == old_nd.mnt->mnt_parent)
+		goto out2;
+
+	if (S_ISDIR(nd->dentry->d_inode->i_mode) !=
+	      S_ISDIR(old_nd.dentry->d_inode->i_mode))
+		goto out2;
+
+	err = -ELOOP;
+	for (p = nd->mnt; p->mnt_parent!=p; p = p->mnt_parent)
+		if (p == old_nd.mnt)
+			goto out2;
+	err = 0;
+
+	detach_mnt(old_nd.mnt, &parent_nd);
+	attach_mnt(old_nd.mnt, nd);
+out2:
+	spin_unlock(&dcache_lock);
+out1:
+	up(&nd->dentry->d_inode->i_zombie);
+out:
+	up(&mount_sem);
+	if (!err)
+		path_release(&parent_nd);
+	path_release(&old_nd);
+	return err;
+}
+
 static int do_add_mount(struct nameidata *nd, char *type, int flags,
 			int mnt_flags, char *name, void *data)
 {
@@ -679,6 +740,8 @@
 				    data_page);
 	else if (flags & MS_BIND)
 		retval = do_loopback(&nd, dev_name, flags & MS_REC);
+	else if (flags & MS_MOVE)
+		retval = do_move_mount(&nd, dev_name);
 	else
 		retval = do_add_mount(&nd, type_page, flags, mnt_flags,
 				      dev_name, data_page);
diff -urN linux-2.4.18-pre6/fs/ntfs/fs.c linux/fs/ntfs/fs.c
--- linux-2.4.18-pre6/fs/ntfs/fs.c	Fri Dec 21 09:42:03 2001
+++ linux/fs/ntfs/fs.c	Wed Jan 23 15:04:33 2002
@@ -1023,8 +1023,9 @@
 		ntfs_error("Unable to set blocksize %d.\n", blocksize);
 		goto ntfs_read_super_vol;
 	}
+	sb->s_blocksize = blocksize;
 	/* Read the super block (boot block). */
-	if (!(bh = bread(sb->s_dev, 0, blocksize))) {
+	if (!(bh = sb_bread(sb, 0))) {
 		ntfs_error("Reading super block failed\n");
 		goto ntfs_read_super_unl;
 	}
@@ -1071,8 +1072,7 @@
 	if (to_read < 1)
 		to_read = 1;
 	for (i = 0; i < to_read; i++) {
-		if (!(bh = bread(sb->s_dev, vol->mft_lcn + i,
-							  vol->cluster_size))) {
+		if (!(bh = sb_bread(sb, vol->mft_lcn + i))) {
 			ntfs_error("Could not read $Mft record 0\n");
 			goto ntfs_read_super_mft;
 		}
diff -urN linux-2.4.18-pre6/fs/ntfs/support.c linux/fs/ntfs/support.c
--- linux-2.4.18-pre6/fs/ntfs/support.c	Fri Dec 21 09:42:03 2001
+++ linux/fs/ntfs/support.c	Wed Jan 23 15:04:33 2002
@@ -169,7 +169,7 @@
 		   buf->do_read ? "get" : "put", cluster, start_offs, length);
 	to_copy = vol->cluster_size - start_offs;
 	while (length) {
-		if (!(bh = bread(sb->s_dev, cluster, vol->cluster_size))) {
+		if (!(bh = sb_bread(sb, cluster))) {
 			ntfs_debug(DEBUG_OTHER, "%s failed\n",
 				   buf->do_read ? "Reading" : "Writing");
 			error = -EIO;
diff -urN linux-2.4.18-pre6/fs/qnx4/bitmap.c linux/fs/qnx4/bitmap.c
--- linux-2.4.18-pre6/fs/qnx4/bitmap.c	Tue Sep  5 14:07:30 2000
+++ linux/fs/qnx4/bitmap.c	Wed Jan 23 15:04:33 2002
@@ -69,7 +69,7 @@
 	struct buffer_head *bh;
 
 	while (total < size) {
-		if ((bh = bread(sb->s_dev, start + offset, QNX4_BLOCK_SIZE)) == NULL) {
+		if ((bh = sb_bread(sb, start + offset)) == NULL) {
 			printk("qnx4: I/O error in counting free blocks\n");
 			break;
 		}
@@ -96,7 +96,7 @@
 	QNX4DEBUG(("qnx4: is_free requesting block [%lu], bitmap in block [%lu]\n",
 		   (unsigned long) block, (unsigned long) start));
 	(void) size;		/* CHECKME */
-	bh = bread(sb->s_dev, start, QNX4_BLOCK_SIZE);
+	bh = sb_bread(sb, start);
 	if (bh == NULL) {
 		return -EIO;
 	}
@@ -124,7 +124,7 @@
 	QNX4DEBUG(("qnx4: set_bitmap requesting block [%lu], bitmap in block [%lu]\n",
 		   (unsigned long) block, (unsigned long) start));
 	(void) size;		/* CHECKME */
-	bh = bread(sb->s_dev, start, QNX4_BLOCK_SIZE);
+	bh = sb_bread(sb, start);
 	if (bh == NULL) {
 		return -EIO;
 	}
diff -urN linux-2.4.18-pre6/fs/qnx4/dir.c linux/fs/qnx4/dir.c
--- linux-2.4.18-pre6/fs/qnx4/dir.c	Fri Aug 11 14:29:02 2000
+++ linux/fs/qnx4/dir.c	Wed Jan 23 15:04:33 2002
@@ -36,7 +36,7 @@
 
 	while (filp->f_pos < inode->i_size) {
 		blknum = qnx4_block_map( inode, filp->f_pos >> QNX4_BLOCK_SIZE_BITS );
-		bh = bread(inode->i_dev, blknum, QNX4_BLOCK_SIZE);
+		bh = sb_bread(inode->i_sb, blknum);
 		if(bh==NULL) {
 			printk(KERN_ERR "qnx4_readdir: bread failed (%ld)\n", blknum);
 			break;
diff -urN linux-2.4.18-pre6/fs/qnx4/fsync.c linux/fs/qnx4/fsync.c
--- linux-2.4.18-pre6/fs/qnx4/fsync.c	Wed Jul  5 21:38:48 2000
+++ linux/fs/qnx4/fsync.c	Wed Jan 23 15:04:33 2002
@@ -24,8 +24,6 @@
 #include <asm/segment.h>
 #include <asm/system.h>
 
-#define blocksize QNX4_BLOCK_SIZE
-
 /*
  * The functions for qnx4 fs file synchronization.
  */
@@ -40,7 +38,7 @@
 	if (!*block)
 		return 0;
 	tmp = *block;
-	bh = get_hash_table(inode->i_dev, *block, blocksize);
+	bh = sb_get_hash_table(inode->i_sb, *block);
 	if (!bh)
 		return 0;
 	if (*block != tmp) {
@@ -74,7 +72,7 @@
 	rc = sync_block(inode, iblock, wait);
 	if (rc)
 		return rc;
-	*bh = bread(inode->i_dev, tmp, blocksize);
+	*bh = sb_bread(inode->i_sb, tmp);
 	if (tmp != *iblock) {
 		brelse(*bh);
 		*bh = NULL;
diff -urN linux-2.4.18-pre6/fs/qnx4/inode.c linux/fs/qnx4/inode.c
--- linux-2.4.18-pre6/fs/qnx4/inode.c	Wed Jan 23 15:04:30 2002
+++ linux/fs/qnx4/inode.c	Wed Jan 23 15:04:33 2002
@@ -95,7 +95,7 @@
 	QNX4DEBUG(("qnx4: write inode 2.\n"));
 	block = ino / QNX4_INODES_PER_BLOCK;
 	lock_kernel();
-	if (!(bh = bread(inode->i_dev, block, QNX4_BLOCK_SIZE))) {
+	if (!(bh = sb_bread(inode->i_sb, block))) {
 		printk("qnx4: major problem: unable to read inode from dev "
 		       "%s\n", kdevname(inode->i_dev));
 		unlock_kernel();
@@ -162,7 +162,7 @@
 	if ( nr >= 0 )
 		nr = qnx4_block_map( inode, nr );
 	if (nr) {
-		result = getblk(inode->i_dev, nr, QNX4_BLOCK_SIZE);
+		result = sb_getblk(inode->i_sb, nr);
 		return result;
 	}
 	if (!create) {
@@ -173,7 +173,7 @@
 	if (!tmp) {
 		return NULL;
 	}
-	result = getblk(inode->i_dev, tmp, QNX4_BLOCK_SIZE);
+	result = sb_getblk(inode->i_sb, tmp);
 	if (tst) {
 		qnx4_free_block(inode->i_sb, tmp);
 		brelse(result);
@@ -243,7 +243,7 @@
 		while ( --nxtnt > 0 ) {
 			if ( ix == 0 ) {
 				// read next xtnt block.
-				bh = bread( inode->i_dev, i_xblk - 1, QNX4_BLOCK_SIZE );
+				bh = sb_bread(inode->i_sb, i_xblk - 1);
 				if ( !bh ) {
 					QNX4DEBUG(("qnx4: I/O error reading xtnt block [%ld])\n", i_xblk - 1));
 					return -EIO;
@@ -307,7 +307,7 @@
 		rd = le32_to_cpu(sb->u.qnx4_sb.sb->RootDir.di_first_xtnt.xtnt_blk) - 1;
 		rl = le32_to_cpu(sb->u.qnx4_sb.sb->RootDir.di_first_xtnt.xtnt_size);
 		for (j = 0; j < rl; j++) {
-			bh = bread(sb->s_dev, rd + j, QNX4_BLOCK_SIZE);	/* root dir, first block */
+			bh = sb_bread(sb, rd + j);	/* root dir, first block */
 			if (bh == NULL) {
 				return "unable to read root entry.";
 			}
@@ -354,7 +354,7 @@
 	/* Check the boot signature. Since the qnx4 code is
 	   dangerous, we should leave as quickly as possible
 	   if we don't belong here... */
-	bh = bread(dev, 0, QNX4_BLOCK_SIZE);
+	bh = sb_bread(s, 0);
 	if (!bh) {
 		printk("qnx4: unable to read the boot sector\n");
 		goto outnobh;
@@ -366,7 +366,7 @@
 	}
 	brelse(bh);
 
-	bh = bread(dev, 1, QNX4_BLOCK_SIZE);
+	bh = sb_bread(s, 1);
 	if (!bh) {
 		printk("qnx4: unable to read the superblock\n");
 		goto outnobh;
@@ -461,7 +461,7 @@
 	}
 	block = ino / QNX4_INODES_PER_BLOCK;
 
-	if (!(bh = bread(inode->i_dev, block, QNX4_BLOCK_SIZE))) {
+	if (!(bh = sb_bread(inode->i_sb, block))) {
 		printk("qnx4: major problem: unable to read inode from dev "
 		       "%s\n", kdevname(inode->i_dev));
 		return;
diff -urN linux-2.4.18-pre6/fs/reiserfs/fix_node.c linux/fs/reiserfs/fix_node.c
--- linux-2.4.18-pre6/fs/reiserfs/fix_node.c	Fri Dec 21 09:42:03 2001
+++ linux/fs/reiserfs/fix_node.c	Wed Jan 23 15:04:33 2002
@@ -920,7 +920,7 @@
   /* Get left neighbor block number. */
   n_left_neighbor_blocknr = B_N_CHILD_NUM(p_s_tb->FL[n_h], n_left_neighbor_position);
   /* Look for the left neighbor in the cache. */
-  if ( (left = get_hash_table(p_s_sb->s_dev, n_left_neighbor_blocknr, p_s_sb->s_blocksize)) ) {
+  if ( (left = sb_get_hash_table(p_s_sb, n_left_neighbor_blocknr)) ) {
 
     RFALSE( buffer_uptodate (left) && ! B_IS_IN_TREE(left),
 	    "vs-8170: left neighbor (%b %z) is not in the tree", left, left);
diff -urN linux-2.4.18-pre6/fs/reiserfs/journal.c linux/fs/reiserfs/journal.c
--- linux-2.4.18-pre6/fs/reiserfs/journal.c	Wed Jan 23 15:04:30 2002
+++ linux/fs/reiserfs/journal.c	Wed Jan 23 15:04:33 2002
@@ -685,7 +685,7 @@
   count = 0 ;
   for (i = 0 ; atomic_read(&(jl->j_commit_left)) > 1 && i < (jl->j_len + 1) ; i++) {  /* everything but commit_bh */
     bn = reiserfs_get_journal_block(s) + (jl->j_start+i) % JOURNAL_BLOCK_COUNT;
-    tbh = get_hash_table(s->s_dev, bn, s->s_blocksize) ;
+    tbh = sb_get_hash_table(s, bn) ;
 
 /* kill this sanity check */
 if (count > (orig_commit_left + 2)) {
@@ -714,7 +714,7 @@
     for (i = 0 ; atomic_read(&(jl->j_commit_left)) > 1 && 
                  i < (jl->j_len + 1) ; i++) {  /* everything but commit_bh */
       bn = reiserfs_get_journal_block(s) + (jl->j_start + i) % JOURNAL_BLOCK_COUNT  ;
-      tbh = get_hash_table(s->s_dev, bn, s->s_blocksize) ;
+      tbh = sb_get_hash_table(s, bn) ;
 
       wait_on_buffer(tbh) ;
       if (!buffer_uptodate(tbh)) {
@@ -1405,8 +1405,7 @@
     offset = d_bh->b_blocknr - reiserfs_get_journal_block(p_s_sb) ;
 
     /* ok, we have a journal description block, lets see if the transaction was valid */
-    c_bh = bread(p_s_sb->s_dev, reiserfs_get_journal_block(p_s_sb) + ((offset + le32_to_cpu(desc->j_len) + 1) % JOURNAL_BLOCK_COUNT), 
-    		p_s_sb->s_blocksize) ;
+    c_bh = sb_bread(p_s_sb, reiserfs_get_journal_block(p_s_sb) + ((offset + le32_to_cpu(desc->j_len) + 1) % JOURNAL_BLOCK_COUNT)) ;
     if (!c_bh)
       return 0 ;
     commit = (struct reiserfs_journal_commit *)c_bh->b_data ;
@@ -1460,7 +1459,7 @@
   unsigned long trans_offset ;
   int i;
 
-  d_bh = bread(p_s_sb->s_dev, cur_dblock, p_s_sb->s_blocksize) ;
+  d_bh = sb_bread(p_s_sb, cur_dblock) ;
   if (!d_bh)
     return 1 ;
   desc = (struct reiserfs_journal_desc *)d_bh->b_data ;
@@ -1484,8 +1483,7 @@
     brelse(d_bh) ;
     return 1 ;
   }
-  c_bh = bread(p_s_sb->s_dev, reiserfs_get_journal_block(p_s_sb) + ((trans_offset + le32_to_cpu(desc->j_len) + 1) % JOURNAL_BLOCK_COUNT), 
-    		p_s_sb->s_blocksize) ;
+  c_bh = sb_bread(p_s_sb, reiserfs_get_journal_block(p_s_sb) + ((trans_offset + le32_to_cpu(desc->j_len) + 1) % JOURNAL_BLOCK_COUNT)) ;
   if (!c_bh) {
     brelse(d_bh) ;
     return 1 ;
@@ -1514,11 +1512,11 @@
   }
   /* get all the buffer heads */
   for(i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) {
-    log_blocks[i] = getblk(p_s_sb->s_dev, reiserfs_get_journal_block(p_s_sb) + (trans_offset + 1 + i) % JOURNAL_BLOCK_COUNT, p_s_sb->s_blocksize);
+    log_blocks[i] = sb_getblk(p_s_sb, reiserfs_get_journal_block(p_s_sb) + (trans_offset + 1 + i) % JOURNAL_BLOCK_COUNT);
     if (i < JOURNAL_TRANS_HALF) {
-      real_blocks[i] = getblk(p_s_sb->s_dev, le32_to_cpu(desc->j_realblock[i]), p_s_sb->s_blocksize) ;
+      real_blocks[i] = sb_getblk(p_s_sb, le32_to_cpu(desc->j_realblock[i])) ;
     } else {
-      real_blocks[i] = getblk(p_s_sb->s_dev, le32_to_cpu(commit->j_realblock[i - JOURNAL_TRANS_HALF]), p_s_sb->s_blocksize) ;
+      real_blocks[i] = sb_getblk(p_s_sb, le32_to_cpu(commit->j_realblock[i - JOURNAL_TRANS_HALF])) ;
     }
     if (real_blocks[i]->b_blocknr >= reiserfs_get_journal_block(p_s_sb) &&
         real_blocks[i]->b_blocknr < (reiserfs_get_journal_block(p_s_sb)+JOURNAL_BLOCK_COUNT)) {
@@ -1619,10 +1617,9 @@
   ** is the first unflushed, and if that transaction is not valid, 
   ** replay is done
   */
-  SB_JOURNAL(p_s_sb)->j_header_bh = bread(p_s_sb->s_dev, 
+  SB_JOURNAL(p_s_sb)->j_header_bh = sb_bread(p_s_sb, 
                                           reiserfs_get_journal_block(p_s_sb) + 
-					  JOURNAL_BLOCK_COUNT, 
-					  p_s_sb->s_blocksize) ;
+					  JOURNAL_BLOCK_COUNT) ;
   if (!SB_JOURNAL(p_s_sb)->j_header_bh) {
     return 1 ;
   }
@@ -1643,7 +1640,7 @@
     ** there is nothing more we can do, and it makes no sense to read 
     ** through the whole log.
     */
-    d_bh = bread(p_s_sb->s_dev, reiserfs_get_journal_block(p_s_sb) + le32_to_cpu(jh->j_first_unflushed_offset), p_s_sb->s_blocksize) ;
+    d_bh = sb_bread(p_s_sb, reiserfs_get_journal_block(p_s_sb) + le32_to_cpu(jh->j_first_unflushed_offset)) ;
     ret = journal_transaction_is_valid(p_s_sb, d_bh, NULL, NULL) ;
     if (!ret) {
       continue_replay = 0 ;
@@ -1663,7 +1660,7 @@
   ** all the valid transactions, and pick out the oldest.
   */
   while(continue_replay && cur_dblock < (reiserfs_get_journal_block(p_s_sb) + JOURNAL_BLOCK_COUNT)) {
-    d_bh = bread(p_s_sb->s_dev, cur_dblock, p_s_sb->s_blocksize) ;
+    d_bh = sb_bread(p_s_sb, cur_dblock) ;
     ret = journal_transaction_is_valid(p_s_sb, d_bh, &oldest_invalid_trans_id, &newest_mount_id) ;
     if (ret == 1) {
       desc = (struct reiserfs_journal_desc *)d_bh->b_data ;
@@ -2543,7 +2540,7 @@
   int cleaned = 0 ;
   
   if (reiserfs_dont_log(th->t_super)) {
-    bh = get_hash_table(p_s_sb->s_dev, blocknr, p_s_sb->s_blocksize) ;
+    bh = sb_get_hash_table(p_s_sb, blocknr) ;
     if (bh && buffer_dirty (bh)) {
       printk ("journal_mark_freed(dont_log): dirty buffer on hash list: %lx %ld\n", bh->b_state, blocknr);
       BUG ();
@@ -2551,7 +2548,7 @@
     brelse (bh);
     return 0 ;
   }
-  bh = get_hash_table(p_s_sb->s_dev, blocknr, p_s_sb->s_blocksize) ;
+  bh = sb_get_hash_table(p_s_sb, blocknr) ;
   /* if it is journal new, we just remove it from this transaction */
   if (bh && buffer_journal_new(bh)) {
     mark_buffer_notjournal_new(bh) ;
@@ -2758,7 +2755,7 @@
   
   rs = SB_DISK_SUPER_BLOCK(p_s_sb) ;
   /* setup description block */
-  d_bh = getblk(p_s_sb->s_dev, reiserfs_get_journal_block(p_s_sb) + SB_JOURNAL(p_s_sb)->j_start, p_s_sb->s_blocksize) ; 
+  d_bh = sb_getblk(p_s_sb, reiserfs_get_journal_block(p_s_sb) + SB_JOURNAL(p_s_sb)->j_start) ; 
   mark_buffer_uptodate(d_bh, 1) ;
   desc = (struct reiserfs_journal_desc *)(d_bh)->b_data ;
   memset(desc, 0, sizeof(struct reiserfs_journal_desc)) ;
@@ -2766,9 +2763,8 @@
   desc->j_trans_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_trans_id) ;
 
   /* setup commit block.  Don't write (keep it clean too) this one until after everyone else is written */
-  c_bh = getblk(p_s_sb->s_dev,  reiserfs_get_journal_block(p_s_sb) + 
-  				        ((SB_JOURNAL(p_s_sb)->j_start + SB_JOURNAL(p_s_sb)->j_len + 1) % JOURNAL_BLOCK_COUNT), 
-					 p_s_sb->s_blocksize) ;
+  c_bh = sb_getblk(p_s_sb,  reiserfs_get_journal_block(p_s_sb) + 
+  				        ((SB_JOURNAL(p_s_sb)->j_start + SB_JOURNAL(p_s_sb)->j_len + 1) % JOURNAL_BLOCK_COUNT)) ;
   commit = (struct reiserfs_journal_commit *)c_bh->b_data ;
   memset(commit, 0, sizeof(struct reiserfs_journal_commit)) ;
   commit->j_trans_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_trans_id) ;
@@ -2856,9 +2852,8 @@
     /* copy all the real blocks into log area.  dirty log blocks */
     if (test_bit(BH_JDirty, &cn->bh->b_state)) {
       struct buffer_head *tmp_bh ;
-      tmp_bh = getblk(p_s_sb->s_dev, reiserfs_get_journal_block(p_s_sb) + 
-		     ((cur_write_start + jindex) % JOURNAL_BLOCK_COUNT), 
-				       p_s_sb->s_blocksize) ;
+      tmp_bh = sb_getblk(p_s_sb, reiserfs_get_journal_block(p_s_sb) + 
+		     ((cur_write_start + jindex) % JOURNAL_BLOCK_COUNT)) ;
       mark_buffer_uptodate(tmp_bh, 1) ;
       memcpy(tmp_bh->b_data, cn->bh->b_data, cn->bh->b_size) ;  
       jindex++ ;
diff -urN linux-2.4.18-pre6/fs/reiserfs/resize.c linux/fs/reiserfs/resize.c
--- linux-2.4.18-pre6/fs/reiserfs/resize.c	Fri Dec 21 09:42:03 2001
+++ linux/fs/reiserfs/resize.c	Wed Jan 23 15:04:33 2002
@@ -39,7 +39,7 @@
 	}
 
 	/* check the device size */
-	bh = bread(s->s_dev, block_count_new - 1, s->s_blocksize);
+	bh = sb_bread(s, block_count_new - 1);
 	if (!bh) {
 		printk("reiserfs_resize: can\'t read last block\n");
 		return -EINVAL;
diff -urN linux-2.4.18-pre6/fs/romfs/inode.c linux/fs/romfs/inode.c
--- linux-2.4.18-pre6/fs/romfs/inode.c	Fri Nov 16 09:45:47 2001
+++ linux/fs/romfs/inode.c	Wed Jan 23 15:04:33 2002
@@ -108,7 +108,7 @@
 	s->u.generic_sbp = (void *) 0;
 	s->s_maxbytes = 0xFFFFFFFF;
 
-	bh = bread(dev, 0, ROMBSIZE);
+	bh = sb_bread(s, 0);
 	if (!bh) {
 		/* XXX merge with other printk? */
                 printk ("romfs: unable to read superblock\n");
@@ -188,7 +188,7 @@
 	if (count > maxsize || offset+count > maxsize)
 		count = maxsize-offset;
 
-	bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);
+	bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
 	if (!bh)
 		return -1;		/* error */
 
@@ -203,7 +203,7 @@
 	while (res < count) {
 		offset += maxsize;
 
-		bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);
+		bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
 		if (!bh)
 			return -1;
 		maxsize = min_t(unsigned long, count - res, ROMBSIZE);
@@ -226,7 +226,7 @@
 	if (offset >= maxsize || count > maxsize || offset+count>maxsize)
 		return -1;
 
-	bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);
+	bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
 	if (!bh)
 		return -1;		/* error */
 
@@ -241,7 +241,7 @@
 		offset += maxsize;
 		dest += maxsize;
 
-		bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);
+		bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
 		if (!bh)
 			return -1;
 		maxsize = min_t(unsigned long, count - res, ROMBSIZE);
diff -urN linux-2.4.18-pre6/fs/super.c linux/fs/super.c
--- linux-2.4.18-pre6/fs/super.c	Wed Jan 23 15:04:30 2002
+++ linux/fs/super.c	Wed Jan 23 15:04:33 2002
@@ -271,6 +271,160 @@
 	return fs;
 }
 
+/**
+ *	alloc_super	-	create new superblock
+ *
+ *	Allocates and initializes a new &struct super_block.  alloc_super()
+ *	returns a pointer new superblock or %NULL if allocation had failed.
+ */
+static struct super_block *alloc_super(void)
+{
+	struct super_block *s = kmalloc(sizeof(struct super_block),  GFP_USER);
+	if (s) {
+		memset(s, 0, sizeof(struct super_block));
+		INIT_LIST_HEAD(&s->s_dirty);
+		INIT_LIST_HEAD(&s->s_locked_inodes);
+		INIT_LIST_HEAD(&s->s_files);
+		INIT_LIST_HEAD(&s->s_instances);
+		init_rwsem(&s->s_umount);
+		sema_init(&s->s_lock, 1);
+		down_write(&s->s_umount);
+		s->s_count = S_BIAS;
+		atomic_set(&s->s_active, 1);
+		sema_init(&s->s_vfs_rename_sem,1);
+		sema_init(&s->s_nfsd_free_path_sem,1);
+		sema_init(&s->s_dquot.dqio_sem, 1);
+		sema_init(&s->s_dquot.dqoff_sem, 1);
+		s->s_maxbytes = MAX_NON_LFS;
+	}
+	return s;
+}
+
+/**
+ *	destroy_super	-	frees a superblock
+ *	@s: superblock to free
+ *
+ *	Frees a superblock.
+ */
+static inline void destroy_super(struct super_block *s)
+{
+	kfree(s);
+}
+
+/* Superblock refcounting  */
+
+/**
+ *	deactivate_super	-	turn an active reference into temporary
+ *	@s: superblock to deactivate
+ *
+ *	Turns an active reference into temporary one.  Returns 0 if there are
+ *	other active references, 1 if we had deactivated the last one.
+ */
+static inline int deactivate_super(struct super_block *s)
+{
+	if (!atomic_dec_and_lock(&s->s_active, &sb_lock))
+		return 0;
+	s->s_count -= S_BIAS-1;
+	spin_unlock(&sb_lock);
+	return 1;
+}
+
+/**
+ *	put_super	-	drop a temporary reference to superblock
+ *	@s: superblock in question
+ *
+ *	Drops a temporary reference, frees superblock if there's no
+ *	references left.
+ */
+static inline void put_super(struct super_block *s)
+{
+	spin_lock(&sb_lock);
+	if (!--s->s_count)
+		destroy_super(s);
+	spin_unlock(&sb_lock);
+}
+
+/**
+ *	grab_super	- acquire an active reference
+ *	@s	- reference we are trying to make active
+ *
+ *	Tries to acquire an active reference.  grab_super() is used when we
+ * 	had just found a superblock in super_blocks or fs_type->fs_supers
+ *	and want to turn it into a full-blown active reference.  grab_super()
+ *	is called with sb_lock held and drops it.  Returns 1 in case of
+ *	success, 0 if we had failed (superblock contents was already dead or
+ *	dying when grab_super() had been called).
+ */
+static int grab_super(struct super_block *s)
+{
+	s->s_count++;
+	spin_unlock(&sb_lock);
+	down_write(&s->s_umount);
+	if (s->s_root) {
+		spin_lock(&sb_lock);
+		if (s->s_count > S_BIAS) {
+			atomic_inc(&s->s_active);
+			s->s_count--;
+			spin_unlock(&sb_lock);
+			return 1;
+		}
+		spin_unlock(&sb_lock);
+	}
+	up_write(&s->s_umount);
+	put_super(s);
+	return 0;
+}
+ 
+/**
+ *	insert_super	-	put superblock on the lists
+ *	@s:	superblock in question
+ *	@type:	filesystem type it will belong to
+ *
+ *	Associates superblock with fs type and puts it on per-type and global
+ *	superblocks' lists.  Should be called with sb_lock held; drops it.
+ */
+static void insert_super(struct super_block *s, struct file_system_type *type)
+{
+	s->s_type = type;
+	list_add(&s->s_list, super_blocks.prev);
+	list_add(&s->s_instances, &type->fs_supers);
+	spin_unlock(&sb_lock);
+	get_filesystem(type);
+}
+
+void put_unnamed_dev(kdev_t dev);	/* should become static */
+
+/**
+ *	remove_super	-	makes superblock unreachable
+ *	@s:	superblock in question
+ *
+ *	Removes superblock from the lists, unlocks it, drop the reference
+ *	and releases the hosting device.  @s should have no active
+ *	references by that time and after remove_super() it's essentially
+ *	in rundown mode - all remaining references are temporary, no new
+ *	reference of any sort are going to appear and all holders of
+ *	temporary ones will eventually drop them.  At that point superblock
+ *	itself will be destroyed; all its contents is already gone.
+ */
+static void remove_super(struct super_block *s)
+{
+	kdev_t dev = s->s_dev;
+	struct block_device *bdev = s->s_bdev;
+	struct file_system_type *fs = s->s_type;
+
+	spin_lock(&sb_lock);
+	list_del(&s->s_list);
+	list_del(&s->s_instances);
+	spin_unlock(&sb_lock);
+	up_write(&s->s_umount);
+	put_super(s);
+	put_filesystem(fs);
+	if (bdev)
+		blkdev_put(bdev, BDEV_FS);
+	else
+		put_unnamed_dev(dev);
+}
+
 struct vfsmount *alloc_vfsmnt(void);
 void free_vfsmnt(struct vfsmount *mnt);
 void set_devname(struct vfsmount *mnt, const char *name);
@@ -279,14 +433,6 @@
 extern struct vfsmount *root_vfsmnt;
 extern int graft_tree(struct vfsmount *mnt, struct nameidata *nd);
 
-static inline void __put_super(struct super_block *sb)
-{
-	spin_lock(&sb_lock);
-	if (!--sb->s_count)
-		kfree(sb);
-	spin_unlock(&sb_lock);
-}
-
 static inline struct super_block * find_super(kdev_t dev)
 {
 	struct list_head *p;
@@ -304,14 +450,7 @@
 void drop_super(struct super_block *sb)
 {
 	up_read(&sb->s_umount);
-	__put_super(sb);
-}
-
-static void put_super(struct super_block *sb)
-{
-	atomic_dec(&sb->s_active);
-	up_write(&sb->s_umount);
-	__put_super(sb);
+	put_super(sb);
 }
 
 static inline void write_super(struct super_block *sb)
@@ -322,7 +461,7 @@
 			sb->s_op->write_super(sb);
 	unlock_super(sb);
 }
- 
+
 /*
  * Note: check the dirty flag before waiting, so we don't
  * hold up the sync while mounting a device. (The newly
@@ -410,37 +549,6 @@
 	return err;
 }
 
-/**
- *	get_empty_super	-	find empty superblocks
- *
- *	Find a superblock with no device assigned. A free superblock is 
- *	found and returned. If neccessary new superblocks are allocated.
- *	%NULL is returned if there are insufficient resources to complete
- *	the request.
- */
- 
-static struct super_block *alloc_super(void)
-{
-	struct super_block *s = kmalloc(sizeof(struct super_block),  GFP_USER);
-	if (s) {
-		memset(s, 0, sizeof(struct super_block));
-		INIT_LIST_HEAD(&s->s_dirty);
-		INIT_LIST_HEAD(&s->s_locked_inodes);
-		INIT_LIST_HEAD(&s->s_files);
-		INIT_LIST_HEAD(&s->s_instances);
-		init_rwsem(&s->s_umount);
-		sema_init(&s->s_lock, 1);
-		s->s_count = 1;
-		atomic_set(&s->s_active, 1);
-		sema_init(&s->s_vfs_rename_sem,1);
-		sema_init(&s->s_nfsd_free_path_sem,1);
-		sema_init(&s->s_dquot.dqio_sem, 1);
-		sema_init(&s->s_dquot.dqoff_sem, 1);
-		s->s_maxbytes = MAX_NON_LFS;
-	}
-	return s;
-}
-
 static struct super_block * read_super(kdev_t dev, struct block_device *bdev,
 				       struct file_system_type *type, int flags,
 				       void *data)
@@ -452,13 +560,8 @@
 	s->s_dev = dev;
 	s->s_bdev = bdev;
 	s->s_flags = flags;
-	s->s_type = type;
 	spin_lock(&sb_lock);
-	list_add (&s->s_list, super_blocks.prev);
-	list_add (&s->s_instances, &type->fs_supers);
-	s->s_count += S_BIAS;
-	spin_unlock(&sb_lock);
-	down_write(&s->s_umount);
+	insert_super(s, type);
 	lock_super(s);
 	if (!type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0))
 		goto out_fail;
@@ -471,16 +574,9 @@
 	return s;
 
 out_fail:
-	s->s_dev = 0;
-	s->s_bdev = 0;
-	s->s_type = NULL;
 	unlock_super(s);
-	spin_lock(&sb_lock);
-	list_del(&s->s_list);
-	list_del(&s->s_instances);
-	s->s_count -= S_BIAS;
-	spin_unlock(&sb_lock);
-	put_super(s);
+	deactivate_super(s);
+	remove_super(s);
 	return NULL;
 }
 
@@ -512,25 +608,6 @@
 			kdevname(dev));
 }
 
-static int grab_super(struct super_block *sb)
-{
-	sb->s_count++;
-	atomic_inc(&sb->s_active);
-	spin_unlock(&sb_lock);
-	down_write(&sb->s_umount);
-	if (sb->s_root) {
-		spin_lock(&sb_lock);
-		if (sb->s_count > S_BIAS) {
-			sb->s_count--;
-			spin_unlock(&sb_lock);
-			return 1;
-		}
-		spin_unlock(&sb_lock);
-	}
-	put_super(sb);
-	return 0;
-}
-
 static struct super_block *get_sb_bdev(struct file_system_type *fs_type,
 	char *dev_name, int flags, void * data)
 {
@@ -574,14 +651,17 @@
 		goto out;
 	check_disk_change(dev);
 	error = -EACCES;
-	if (!(flags & MS_RDONLY) && is_read_only(dev))
-		goto out1;
+	if (!(flags & MS_RDONLY) && is_read_only(dev)) {
+		blkdev_put(bdev, BDEV_FS);
+		goto out;
+	}
 
 	error = -ENOMEM;
 	s = alloc_super();
-	if (!s)
-		goto out1;
-	down_write(&s->s_umount);
+	if (!s) {
+		blkdev_put(bdev, BDEV_FS);
+		goto out;
+	}
 
 	error = -EBUSY;
 restart:
@@ -594,12 +674,13 @@
 		if (old->s_type != fs_type ||
 		    ((flags ^ old->s_flags) & MS_RDONLY)) {
 			spin_unlock(&sb_lock);
-			put_super(s);
-			goto out1;
+			destroy_super(s);
+			blkdev_put(bdev, BDEV_FS);
+			goto out;
 		}
 		if (!grab_super(old))
 			goto restart;
-		put_super(s);
+		destroy_super(s);
 		blkdev_put(bdev, BDEV_FS);
 		path_release(&nd);
 		return old;
@@ -607,12 +688,7 @@
 	s->s_dev = dev;
 	s->s_bdev = bdev;
 	s->s_flags = flags;
-	s->s_type = fs_type;
-	list_add (&s->s_list, super_blocks.prev);
-	list_add (&s->s_instances, &fs_type->fs_supers);
-	s->s_count += S_BIAS;
-
-	spin_unlock(&sb_lock);
+	insert_super(s, fs_type);
 
 	error = -EINVAL;
 	lock_super(s);
@@ -620,23 +696,13 @@
 		goto out_fail;
 	s->s_flags |= MS_ACTIVE;
 	unlock_super(s);
-	get_filesystem(fs_type);
 	path_release(&nd);
 	return s;
 
 out_fail:
-	s->s_dev = 0;
-	s->s_bdev = 0;
-	s->s_type = NULL;
 	unlock_super(s);
-	spin_lock(&sb_lock);
-	list_del(&s->s_list);
-	list_del(&s->s_instances);
-	s->s_count -= S_BIAS;
-	spin_unlock(&sb_lock);
-	put_super(s);
-out1:
-	blkdev_put(bdev, BDEV_FS);
+	deactivate_super(s);
+	remove_super(s);
 out:
 	path_release(&nd);
 	return ERR_PTR(error);
@@ -652,11 +718,8 @@
 		struct super_block * sb;
 		error = -EINVAL;
 		sb = read_super(dev, NULL, fs_type, flags, data);
-		if (sb) {
-			get_filesystem(fs_type);
+		if (sb)
 			return sb;
-		}
-		put_unnamed_dev(dev);
 	}
 	return ERR_PTR(error);
 }
@@ -667,7 +730,6 @@
 	struct super_block * s = alloc_super();
 	if (!s)
 		return ERR_PTR(-ENOMEM);
-	down_write(&s->s_umount);
 	/*
 	 * Get the superblock of kernel-wide instance, but
 	 * keep the reference to fs_type.
@@ -680,61 +742,43 @@
 				s_instances);
 		if (!grab_super(old))
 			goto retry;
-		put_super(s);
+		destroy_super(s);
 		do_remount_sb(old, flags, data);
 		return old;
 	} else {
 		kdev_t dev = get_unnamed_dev();
 		if (!dev) {
 			spin_unlock(&sb_lock);
-			put_super(s);
+			destroy_super(s);
 			return ERR_PTR(-EMFILE);
 		}
 		s->s_dev = dev;
 		s->s_flags = flags;
-		s->s_type = fs_type;
-		list_add (&s->s_list, super_blocks.prev);
-		list_add (&s->s_instances, &fs_type->fs_supers);
-		s->s_count += S_BIAS;
-		spin_unlock(&sb_lock);
+		insert_super(s, fs_type);
 		lock_super(s);
 		if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0))
 			goto out_fail;
 		s->s_flags |= MS_ACTIVE;
 		unlock_super(s);
-		get_filesystem(fs_type);
 		return s;
 
 	out_fail:
-		s->s_dev = 0;
-		s->s_bdev = 0;
-		s->s_type = NULL;
 		unlock_super(s);
-		spin_lock(&sb_lock);
-		list_del(&s->s_list);
-		list_del(&s->s_instances);
-		s->s_count -= S_BIAS;
-		spin_unlock(&sb_lock);
-		put_super(s);
-		put_unnamed_dev(dev);
+		deactivate_super(s);
+		remove_super(s);
 		return ERR_PTR(-EINVAL);
 	}
 }
 
 void kill_super(struct super_block *sb)
 {
-	struct block_device *bdev;
-	kdev_t dev;
 	struct dentry *root = sb->s_root;
 	struct file_system_type *fs = sb->s_type;
 	struct super_operations *sop = sb->s_op;
 
-	if (!atomic_dec_and_lock(&sb->s_active, &sb_lock))
+	if (!deactivate_super(sb))
 		return;
 
-	sb->s_count -= S_BIAS;
-	spin_unlock(&sb_lock);
-
 	down_write(&sb->s_umount);
 	lock_kernel();
 	sb->s_root = NULL;
@@ -760,24 +804,9 @@
 			"Self-destruct in 5 seconds.  Have a nice day...\n");
 	}
 
-	dev = sb->s_dev;
-	sb->s_dev = 0;		/* Free the superblock */
-	bdev = sb->s_bdev;
-	sb->s_bdev = NULL;
-	put_filesystem(fs);
-	sb->s_type = NULL;
-	unlock_super(sb);
 	unlock_kernel();
-	if (bdev)
-		blkdev_put(bdev, BDEV_FS);
-	else
-		put_unnamed_dev(dev);
-	spin_lock(&sb_lock);
-	list_del(&sb->s_list);
-	list_del(&sb->s_instances);
-	spin_unlock(&sb_lock);
-	atomic_inc(&sb->s_active);
-	put_super(sb);
+	unlock_super(sb);
+	remove_super(sb);
 }
 
 /*
@@ -1018,6 +1047,7 @@
 		 * Allow the user to distinguish between failed open
 		 * and bad superblock on root device.
 		 */
+Eio:
 		printk ("VFS: Cannot open root device \"%s\" or %s\n",
 			root_device_name, kdevname (ROOT_DEV));
 		printk ("Please append a correct \"root=\" boot option\n");
@@ -1040,11 +1070,17 @@
 		struct file_system_type * fs_type = get_fs_type(p);
 		if (!fs_type)
   			continue;
+		atomic_inc(&bdev->bd_count);
+		retval = blkdev_get(bdev, mode, 0, BDEV_FS);
+		if (retval)
+			goto Eio;
   		sb = read_super(ROOT_DEV, bdev, fs_type,
 				root_mountflags, root_mount_data);
-		if (sb) 
-			goto mount_it;
 		put_filesystem(fs_type);
+		if (sb) {
+			blkdev_put(bdev, BDEV_FS);
+			goto mount_it;
+		}
 	}
 	panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV));
 
diff -urN linux-2.4.18-pre6/fs/sysv/ChangeLog linux/fs/sysv/ChangeLog
--- linux-2.4.18-pre6/fs/sysv/ChangeLog	Fri Dec 21 09:42:03 2001
+++ linux/fs/sysv/ChangeLog	Wed Jan 23 15:04:33 2002
@@ -1,3 +1,9 @@
+Thu Jan 10 2002  Andrew Morton  <akpm@zip.com.au>
+
+	* dir_commit_chunk(): call writeout_one_page() as well as
+	  waitfor_one_page() for IS_SYNC directories, so that we
+	  actually do sync the directory.
+
 Sat Dec 15 2001  Christoph Hellwig  <hch@caldera.de>
 
 	* inode.c (sysv_read_inode): Mark inode as bad in case of failure.
@@ -19,4 +25,5 @@
 	  include/linux/sysv_fs_sb.h:
 	Remove symlink faking.	Noone really wants to use these as
 	linux filesystems and native OSes don't support it anyway.
+
 
diff -urN linux-2.4.18-pre6/fs/sysv/balloc.c linux/fs/sysv/balloc.c
--- linux-2.4.18-pre6/fs/sysv/balloc.c	Sun Sep  2 10:34:36 2001
+++ linux/fs/sysv/balloc.c	Wed Jan 23 15:04:33 2002
@@ -73,7 +73,7 @@
 	 */
 	if (count == sb->sv_flc_size || count == 0) {
 		block += sb->sv_block_base;
-		bh = getblk(sb->s_dev, block, sb->s_blocksize);
+		bh = sb_getblk(sb, block);
 		if (!bh) {
 			printk("sysv_free_block: getblk() failed\n");
 			unlock_super(sb);
@@ -125,7 +125,7 @@
 		unsigned count;
 
 		block += sb->sv_block_base;
-		if (!(bh = bread(sb->s_dev, block, sb->s_blocksize))) {
+		if (!(bh = sb_bread(sb, block))) {
 			printk("sysv_new_block: cannot read free-list block\n");
 			/* retry this same block next time */
 			*sb->sv_bcache_count = cpu_to_fs16(sb, 1);
@@ -196,7 +196,7 @@
 		if (block < sb->sv_firstdatazone || block >= sb->sv_nzones)
 			goto Einval;
 		block += sb->sv_block_base;
-		bh = bread(sb->s_dev, block, sb->s_blocksize);
+		bh = sb_bread(sb, block);
 		if (!bh)
 			goto Eio;
 		n = fs16_to_cpu(sb, *(u16*)bh->b_data);
diff -urN linux-2.4.18-pre6/fs/sysv/dir.c linux/fs/sysv/dir.c
--- linux-2.4.18-pre6/fs/sysv/dir.c	Fri Nov  9 13:45:35 2001
+++ linux/fs/sysv/dir.c	Wed Jan 23 15:04:33 2002
@@ -43,8 +43,13 @@
 
 	dir->i_version = ++event;
 	page->mapping->a_ops->commit_write(NULL, page, from, to);
-	if (IS_SYNC(dir))
-		err = waitfor_one_page(page);
+	if (IS_SYNC(dir)) {
+		int err2;
+		err = writeout_one_page(page);
+		err2 = waitfor_one_page(page);
+		if (err == 0)
+			err = err2;
+	}
 	return err;
 }
 
diff -urN linux-2.4.18-pre6/fs/sysv/ialloc.c linux/fs/sysv/ialloc.c
--- linux-2.4.18-pre6/fs/sysv/ialloc.c	Fri Nov  9 13:45:35 2001
+++ linux/fs/sysv/ialloc.c	Wed Jan 23 15:04:33 2002
@@ -55,7 +55,7 @@
 	struct sysv_inode *res;
 	int block = sb->sv_firstinodezone + sb->sv_block_base;
 	block += (ino-1) >> sb->sv_inodes_per_block_bits;
-	*bh = bread(sb->s_dev, block, sb->s_blocksize);
+	*bh = sb_bread(sb, block);
 	if (!*bh)
 		return NULL;
 	res = (struct sysv_inode *) (*bh)->b_data;
diff -urN linux-2.4.18-pre6/fs/sysv/itree.c linux/fs/sysv/itree.c
--- linux-2.4.18-pre6/fs/sysv/itree.c	Mon Jul  2 14:03:04 2001
+++ linux/fs/sysv/itree.c	Wed Jan 23 15:04:33 2002
@@ -86,8 +86,7 @@
 			    Indirect chain[],
 			    int *err)
 {
-	kdev_t dev = inode->i_dev;
-	int size = inode->i_sb->s_blocksize;
+	struct super_block *sb = inode->i_sb;
 	Indirect *p = chain;
 	struct buffer_head *bh;
 
@@ -96,8 +95,8 @@
 	if (!p->key)
 		goto no_block;
 	while (--depth) {
-		int block = block_to_cpu(inode->i_sb, p->key);
-		bh = bread(dev, block, size);
+		int block = block_to_cpu(sb, p->key);
+		bh = sb_bread(sb, block);
 		if (!bh)
 			goto failure;
 		if (!verify_chain(chain, p))
@@ -139,7 +138,7 @@
 		 * the pointer to new one, then send parent to disk.
 		 */
 		parent = block_to_cpu(inode->i_sb, branch[n-1].key);
-		bh = getblk(inode->i_dev, parent, blocksize);
+		bh = sb_getblk(inode->i_sb, parent);
 		lock_buffer(bh);
 		memset(bh->b_data, 0, blocksize);
 		branch[n].bh = bh;
@@ -336,7 +335,7 @@
 				continue;
 			*p = 0;
 			block = block_to_cpu(sb, nr);
-			bh = bread(inode->i_dev, block, sb->s_blocksize);
+			bh = sb_bread(sb, block);
 			if (!bh)
 				continue;
 			free_branches(inode, (u32*)bh->b_data,
diff -urN linux-2.4.18-pre6/fs/sysv/super.c linux/fs/sysv/super.c
--- linux-2.4.18-pre6/fs/sysv/super.c	Fri Dec 21 09:42:03 2001
+++ linux/fs/sysv/super.c	Wed Jan 23 15:04:33 2002
@@ -362,11 +362,12 @@
 	if (64 != sizeof (struct sysv_inode))
 		panic("sysv fs: bad i-node size");
 	set_blocksize(dev,BLOCK_SIZE);
+	sb->s_blocksize = BLOCK_SIZE;
 	sb->sv_block_base = 0;
 
 	for (i = 0; i < sizeof(flavours)/sizeof(flavours[0]) && !size; i++) {
 		brelse(bh);
-		bh = bread(dev, flavours[i].block, BLOCK_SIZE);
+		bh = sb_bread(sb, flavours[i].block);
 		if (!bh)
 			continue;
 		size = flavours[i].test(sb, bh);
@@ -380,8 +381,9 @@
 			blocknr = bh->b_blocknr << 1;
 			brelse(bh);
 			set_blocksize(dev, 512);
-			bh1 = bread(dev, blocknr, 512);
-			bh = bread(dev, blocknr + 1, 512);
+			sb->s_blocksize = 512;
+			bh1 = sb_bread(sb, blocknr);
+			bh = sb_bread(sb, blocknr + 1);
 			break;
 		case 2:
 			bh1 = bh;
@@ -390,7 +392,8 @@
 			blocknr = bh->b_blocknr >> 1;
 			brelse(bh);
 			set_blocksize(dev, 2048);
-			bh1 = bh = bread(dev, blocknr, 2048);
+			sb->s_blocksize = 2048;
+			bh1 = bh = sb_bread(sb, blocknr);
 			break;
 		default:
 			goto Ebadsize;
@@ -441,8 +444,9 @@
 	sb->sv_bytesex = BYTESEX_PDP;
 
 	set_blocksize(dev, 512);
+	sb->s_blocksize = 512;
 
-	if ((bh = bread(dev, 1, 512)) == NULL) {
+	if ((bh = sb_bread(sb, 1)) == NULL) {
 		if (!silent)
 			printk("VFS: unable to read V7 FS superblock on "
 			       "device %s.\n", bdevname(dev));
@@ -458,7 +462,7 @@
 
 	/* plausibility check on root inode: it is a directory,
 	   with a nonzero size that is a multiple of 16 */
-	if ((bh2 = bread(dev, 2, 512)) == NULL)
+	if ((bh2 = sb_bread(sb, 2)) == NULL)
 		goto failed;
 	v7i = (struct sysv_inode *)(bh2->b_data + 64);
 	if ((fs16_to_cpu(sb,v7i->i_mode) & ~0777) != S_IFDIR ||
diff -urN linux-2.4.18-pre6/fs/udf/balloc.c linux/fs/udf/balloc.c
--- linux-2.4.18-pre6/fs/udf/balloc.c	Thu Oct 11 08:59:24 2001
+++ linux/fs/udf/balloc.c	Wed Jan 23 15:04:33 2002
@@ -98,7 +98,7 @@
 	loc.logicalBlockNum = bitmap->s_extPosition;
 	loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
 
-	bh = udf_tread(sb, udf_get_lb_pblock(sb, loc, block), sb->s_blocksize);
+	bh = udf_tread(sb, udf_get_lb_pblock(sb, loc, block));
 	if (!bh)
 	{
 		retval = -EIO;
@@ -463,7 +463,7 @@
 	elen = 0;
 	obloc = nbloc = UDF_I_LOCATION(table);
 
-	obh = nbh = udf_tread(sb, udf_get_lb_pblock(sb, nbloc, 0), sb->s_blocksize);
+	obh = nbh = udf_tread(sb, udf_get_lb_pblock(sb, nbloc, 0));
 	atomic_inc(&nbh->b_count);
 
 	while (count && (etype =
@@ -571,8 +571,7 @@
 			elen -= sb->s_blocksize;
 
 			if (!(nbh = udf_tread(sb,
-				udf_get_lb_pblock(sb, nbloc, 0),
-				sb->s_blocksize)))
+				udf_get_lb_pblock(sb, nbloc, 0))))
 			{
 				udf_release_data(obh);
 				goto error_return;
@@ -689,7 +688,7 @@
 	extoffset = sizeof(struct UnallocatedSpaceEntry);
 	bloc = UDF_I_LOCATION(table);
 
-	bh = udf_tread(sb, udf_get_lb_pblock(sb, bloc, 0), sb->s_blocksize);
+	bh = udf_tread(sb, udf_get_lb_pblock(sb, bloc, 0));
 	eloc.logicalBlockNum = 0xFFFFFFFF;
 
 	while (first_block != eloc.logicalBlockNum && (etype =
@@ -766,7 +765,7 @@
 	extoffset = sizeof(struct UnallocatedSpaceEntry);
 	bloc = UDF_I_LOCATION(table);
 
-	goal_bh = bh = udf_tread(sb, udf_get_lb_pblock(sb, bloc, 0), sb->s_blocksize);
+	goal_bh = bh = udf_tread(sb, udf_get_lb_pblock(sb, bloc, 0));
 	atomic_inc(&goal_bh->b_count);
 
 	while (spread && (etype =
diff -urN linux-2.4.18-pre6/fs/udf/dir.c linux/fs/udf/dir.c
--- linux-2.4.18-pre6/fs/udf/dir.c	Thu Oct 11 08:59:24 2001
+++ linux/fs/udf/dir.c	Wed Jan 23 15:04:33 2002
@@ -146,7 +146,7 @@
 		return -ENOENT;
 	}
 
-	if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+	if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block)))
 	{
 		udf_release_data(bh);
 		return -EIO;
@@ -160,7 +160,7 @@
 		for (num=0; i>0; i--)
 		{
 			block = udf_get_lb_pblock(dir->i_sb, eloc, offset+i);
-			tmp = udf_tgetblk(dir->i_sb, block, dir->i_sb->s_blocksize);
+			tmp = udf_tgetblk(dir->i_sb, block);
 			if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
 				bha[num++] = tmp;
 			else
diff -urN linux-2.4.18-pre6/fs/udf/directory.c linux/fs/udf/directory.c
--- linux-2.4.18-pre6/fs/udf/directory.c	Mon Jun 11 19:15:27 2001
+++ linux/fs/udf/directory.c	Wed Jan 23 15:04:33 2002
@@ -60,7 +60,7 @@
 		block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
 		if (!block)
 			return NULL;
-		if (!(*bh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+		if (!(*bh = udf_tread(dir->i_sb, block)))
 			return NULL;
 	}
 	else if (*offset > dir->i_sb->s_blocksize)
@@ -74,7 +74,7 @@
 		block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
 		if (!block)
 			return NULL;
-		if (!((*bh) = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+		if (!((*bh) = udf_tread(dir->i_sb, block)))
 			return NULL;
 
 		memcpy((Uint8 *)ad + remainder, (*bh)->b_data, ad_size - remainder);
@@ -117,7 +117,7 @@
 			*extoffset = lextoffset;
 
 		udf_release_data(fibh->sbh);
-		if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+		if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
 			return NULL;
 		fibh->soffset = fibh->eoffset = 0;
 
@@ -129,7 +129,7 @@
 			for (num=0; i>0; i--)
 			{
 				block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset+i);
-				tmp = udf_tgetblk(dir->i_sb, block, dir->i_sb->s_blocksize);
+				tmp = udf_tgetblk(dir->i_sb, block);
 				if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
 					bha[num++] = tmp;
 				else
@@ -183,7 +183,7 @@
 		fibh->soffset -= dir->i_sb->s_blocksize;
 		fibh->eoffset -= dir->i_sb->s_blocksize;
 
-		if (!(fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+		if (!(fibh->ebh = udf_tread(dir->i_sb, block)))
 			return NULL;
 
 		if (sizeof(struct FileIdentDesc) > - fibh->soffset)
diff -urN linux-2.4.18-pre6/fs/udf/file.c linux/fs/udf/file.c
--- linux-2.4.18-pre6/fs/udf/file.c	Thu Oct 11 08:59:24 2001
+++ linux/fs/udf/file.c	Wed Jan 23 15:04:33 2002
@@ -57,7 +57,7 @@
 	kaddr = kmap(page);
 	memset(kaddr, 0, PAGE_CACHE_SIZE);
 	block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
-	bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize);
+	bh = sb_bread(inode->i_sb, block);
 	memcpy(kaddr, bh->b_data + udf_ext0_offset(inode), inode->i_size);
 	brelse(bh);
 	flush_dcache_page(page);
@@ -80,7 +80,7 @@
 
 	kaddr = kmap(page);
 	block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
-	bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize);
+	bh = sb_bread(inode->i_sb, block);
 	memcpy(bh->b_data + udf_ext0_offset(inode), kaddr, inode->i_size);
 	mark_buffer_dirty(bh);
 	brelse(bh);
@@ -105,7 +105,7 @@
 	char *kaddr = page_address(page);
 
 	block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
-	bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize);
+	bh = sb_bread(inode->i_sb, block);
 	memcpy(bh->b_data + udf_file_entry_alloc_offset(inode) + offset,
 		kaddr + offset, to-offset);
 	mark_buffer_dirty(bh);
@@ -246,8 +246,7 @@
 
 	/* ok, we need to read the inode */
 	bh = udf_tread(inode->i_sb,
-		udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0),
-		inode->i_sb->s_blocksize);
+		udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0));
 
 	if (!bh)
 	{
diff -urN linux-2.4.18-pre6/fs/udf/inode.c linux/fs/udf/inode.c
--- linux-2.4.18-pre6/fs/udf/inode.c	Fri Oct 12 13:48:42 2001
+++ linux/fs/udf/inode.c	Wed Jan 23 15:04:33 2002
@@ -184,7 +184,7 @@
 	}
 
 	block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
-	bh = udf_tread(inode->i_sb, block, inode->i_sb->s_blocksize);
+	bh = udf_tread(inode->i_sb, block);
 	if (!bh)
 		return;
 	page = grab_cache_page(inode->i_mapping, 0);
@@ -251,10 +251,10 @@
 		UDF_I_LOCATION(inode).partitionReferenceNum, 0);
 	if (!newblock)
 		return NULL;
-	sbh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+	sbh = udf_tread(inode->i_sb, inode->i_ino);
 	if (!sbh)
 		return NULL;
-	dbh = udf_tgetblk(inode->i_sb, newblock, inode->i_sb->s_blocksize);
+	dbh = udf_tgetblk(inode->i_sb, newblock);
 	if (!dbh)
 		return NULL;
 	lock_buffer(dbh);
@@ -382,7 +382,7 @@
 	if (!*err && buffer_mapped(&dummy))
 	{
 		struct buffer_head *bh;
-		bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
+		bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
 		if (buffer_new(&dummy))
 		{
 			lock_buffer(bh);
@@ -886,8 +886,7 @@
 				udf_file_entry_alloc_offset(inode);
 
 			if ((bh = udf_tread(inode->i_sb,
-				udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0),
-				inode->i_sb->s_blocksize)))
+				udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0))))
 			{
 				memset(bh->b_data + offset, 0x00, inode->i_sb->s_blocksize - offset);
 				mark_buffer_dirty(bh);
@@ -1322,8 +1321,7 @@
 	int err = 0;
 
 	bh = udf_tread(inode->i_sb,
-		udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0),
-		inode->i_sb->s_blocksize);
+		udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0));
 
 	if (!bh)
 	{
@@ -1624,8 +1622,7 @@
 	if (!(*bh))
 	{
 		if (!(*bh = udf_tread(inode->i_sb,
-			udf_get_lb_pblock(inode->i_sb, *bloc, 0),
-			inode->i_sb->s_blocksize)))
+			udf_get_lb_pblock(inode->i_sb, *bloc, 0))))
 		{
 			udf_debug("reading block %d failed!\n",
 				udf_get_lb_pblock(inode->i_sb, *bloc, 0));
@@ -1653,7 +1650,7 @@
 			return -1;
 		}
 		if (!(nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
-			*bloc, 0), inode->i_sb->s_blocksize)))
+			*bloc, 0))))
 		{
 			return -1;
 		}
@@ -1759,8 +1756,7 @@
 	if (!(bh))
 	{
 		if (!(bh = udf_tread(inode->i_sb,
-			udf_get_lb_pblock(inode->i_sb, bloc, 0),
-			inode->i_sb->s_blocksize)))
+			udf_get_lb_pblock(inode->i_sb, bloc, 0))))
 		{
 			udf_debug("reading block %d failed!\n",
 				udf_get_lb_pblock(inode->i_sb, bloc, 0));
@@ -1828,8 +1824,7 @@
 	if (!(*bh))
 	{
 		if (!(*bh = udf_tread(inode->i_sb,
-			udf_get_lb_pblock(inode->i_sb, *bloc, 0),
-			inode->i_sb->s_blocksize)))
+			udf_get_lb_pblock(inode->i_sb, *bloc, 0))))
 		{
 			udf_debug("reading block %d failed!\n",
 				udf_get_lb_pblock(inode->i_sb, *bloc, 0));
@@ -1951,8 +1946,7 @@
 	if (!(*bh))
 	{
 		if (!(*bh = udf_tread(inode->i_sb,
-			udf_get_lb_pblock(inode->i_sb, *bloc, 0),
-			inode->i_sb->s_blocksize)))
+			udf_get_lb_pblock(inode->i_sb, *bloc, 0))))
 		{
 			udf_debug("reading block %d failed!\n",
 				udf_get_lb_pblock(inode->i_sb, *bloc, 0));
@@ -2033,8 +2027,7 @@
 	if (!bh)
 	{
 		if (!(bh = udf_tread(inode->i_sb,
-			udf_get_lb_pblock(inode->i_sb, bloc, 0),
-			inode->i_sb->s_blocksize)))
+			udf_get_lb_pblock(inode->i_sb, bloc, 0))))
 		{
 			udf_debug("reading block %d failed!\n",
 				udf_get_lb_pblock(inode->i_sb, bloc, 0));
@@ -2068,8 +2061,7 @@
 	if (!(nbh))
 	{
 		if (!(nbh = udf_tread(inode->i_sb,
-			udf_get_lb_pblock(inode->i_sb, nbloc, 0),
-			inode->i_sb->s_blocksize)))
+			udf_get_lb_pblock(inode->i_sb, nbloc, 0))))
 		{
 			udf_debug("reading block %d failed!\n",
 				udf_get_lb_pblock(inode->i_sb, nbloc, 0));
diff -urN linux-2.4.18-pre6/fs/udf/misc.c linux/fs/udf/misc.c
--- linux-2.4.18-pre6/fs/udf/misc.c	Mon Jun 11 19:15:27 2001
+++ linux/fs/udf/misc.c	Wed Jan 23 15:04:33 2002
@@ -67,21 +67,21 @@
 #if defined(__linux__) && defined(__KERNEL__)
 
 extern struct buffer_head *
-udf_tgetblk(struct super_block *sb, int block, int size)
+udf_tgetblk(struct super_block *sb, int block)
 {
 	if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
-		return getblk(sb->s_dev, udf_fixed_to_variable(block), size);
+		return sb_getblk(sb, udf_fixed_to_variable(block));
 	else
-		return getblk(sb->s_dev, block, size);
+		return sb_getblk(sb, block);
 }
 
 extern struct buffer_head *
-udf_tread(struct super_block *sb, int block, int size)
+udf_tread(struct super_block *sb, int block)
 {
 	if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
-		return bread(sb->s_dev, udf_fixed_to_variable(block), size);
+		return sb_bread(sb, udf_fixed_to_variable(block));
 	else
-		return bread(sb->s_dev, block, size);
+		return sb_bread(sb, block);
 }
 
 extern struct GenericAttrFormat *
@@ -92,7 +92,7 @@
 	long_ad eaicb;
 	int offset;
 
-	*bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+	*bh = udf_tread(inode->i_sb, inode->i_ino);
 
 	if (UDF_I_EXTENDED_FE(inode) == 0)
 	{
@@ -208,7 +208,7 @@
 	long_ad eaicb;
 	Uint32 offset;
 
-	*bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+	*bh = udf_tread(inode->i_sb, inode->i_ino);
 
 	if (UDF_I_EXTENDED_FE(inode) == 0)
 	{
@@ -273,7 +273,7 @@
 	struct buffer_head *bh = NULL;
 
 	/* Read the block */
-	bh = udf_tread(sb, block+offset, sb->s_blocksize);
+	bh = udf_tread(sb, block+offset);
 	if (!bh)
 	{
 		printk(KERN_ERR "udf: udf_read_untagged(%p,%d,%d) failed\n",
@@ -305,7 +305,7 @@
 	if (block == 0xFFFFFFFF)
 		return NULL;
 
-	bh = udf_tread(sb, block, sb->s_blocksize);
+	bh = udf_tread(sb, block);
 	if (!bh)
 	{
 		udf_debug("block=%d, location=%d: read failed\n", block, location);
diff -urN linux-2.4.18-pre6/fs/udf/namei.c linux/fs/udf/namei.c
--- linux-2.4.18-pre6/fs/udf/namei.c	Thu Oct 11 08:59:24 2001
+++ linux/fs/udf/namei.c	Wed Jan 23 15:04:33 2002
@@ -183,7 +183,7 @@
 		return NULL;
 	}
 
-	if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+	if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
 	{
 		udf_release_data(bh);
 		return NULL;
@@ -404,7 +404,7 @@
 		else
 			offset = 0;
 
-		if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+		if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
 		{
 			udf_release_data(bh);
 			*err = -EIO;
@@ -488,7 +488,7 @@
 		block = udf_get_lb_pblock(dir->i_sb, UDF_I_LOCATION(dir), 0);
 		if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
 		{
-			fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize);
+			fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
 			fibh->soffset = fibh->eoffset = udf_file_entry_alloc_offset(dir);
 		}
 		else
@@ -803,7 +803,7 @@
 		return 0;
 	}
 
-	if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+	if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block)))
 		return 0;
 
 	while ( (f_pos < size) )
@@ -964,7 +964,7 @@
 
 		block = udf_get_pblock(inode->i_sb, block,
 			UDF_I_LOCATION(inode).partitionReferenceNum, 0);
-		bh = udf_tread(inode->i_sb, block, inode->i_sb->s_blocksize);
+		bh = udf_tread(inode->i_sb, block);
 		lock_buffer(bh);
 		memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
 		mark_buffer_uptodate(bh, 1);
@@ -974,7 +974,7 @@
 	else
 	{
 		block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
-		bh = udf_tread(inode->i_sb, block, inode->i_sb->s_blocksize);
+		bh = udf_tread(inode->i_sb, block);
 	}
 	ea = bh->b_data + udf_ext0_offset(inode);
 
diff -urN linux-2.4.18-pre6/fs/udf/partition.c linux/fs/udf/partition.c
--- linux-2.4.18-pre6/fs/udf/partition.c	Mon Jun 11 19:15:27 2001
+++ linux/fs/udf/partition.c	Wed Jan 23 15:04:33 2002
@@ -76,7 +76,7 @@
 
 	loc = udf_block_map(UDF_SB_VAT(sb), newblock);
 
-	if (!(bh = bread(sb->s_dev, loc, sb->s_blocksize)))
+	if (!(bh = sb_bread(sb, loc)))
 	{
 		udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n",
 			sb, block, partition, loc, index);
diff -urN linux-2.4.18-pre6/fs/udf/super.c linux/fs/udf/super.c
--- linux-2.4.18-pre6/fs/udf/super.c	Thu Oct 25 00:02:26 2001
+++ linux/fs/udf/super.c	Wed Jan 23 15:04:33 2002
@@ -412,7 +412,7 @@
 	for (;!nsr02 && !nsr03; sector += sectorsize)
 	{
 		/* Read a block */
-		bh = udf_tread(sb, sector >> sb->s_blocksize_bits, sb->s_blocksize);
+		bh = udf_tread(sb, sector >> sb->s_blocksize_bits);
 		if (!bh)
 			break;
 
@@ -525,7 +525,7 @@
 
 		for (i=0; (!lastblock && i<sizeof(last)/sizeof(int)); i++)
 		{
-			if (last[i] < 0 || !(bh = bread(sb->s_dev, last[i], sb->s_blocksize)))
+			if (last[i] < 0 || !(bh = sb_bread(sb, last[i])))
 			{
 				ident = location = 0;
 			}
@@ -560,7 +560,7 @@
 			}
 			else
 			{
-				if (last[i] < 256 || !(bh = bread(sb->s_dev, last[i] - 256, sb->s_blocksize)))
+				if (last[i] < 256 || !(bh = sb_bread(sb, last[i] - 256)))
 				{
 					ident = location = 0;
 				}
@@ -579,8 +579,7 @@
 				}
 				else
 				{
-					if (last[i] < 312 + UDF_SB_SESSION(sb) || !(bh = bread(sb->s_dev, last[i] - 312 - UDF_SB_SESSION(sb),
-						sb->s_blocksize)))
+					if (last[i] < 312 + UDF_SB_SESSION(sb) || !(bh = sb_bread(sb, last[i] - 312 - UDF_SB_SESSION(sb))))
 					{
 						ident = location = 0;
 					}
@@ -606,7 +605,7 @@
 	if (!lastblock)
 	{
 		/* We havn't found the lastblock. check 312 */
-		if ((bh = bread(sb->s_dev, 312 + UDF_SB_SESSION(sb), sb->s_blocksize)))
+		if ((bh = sb_bread(sb, 312 + UDF_SB_SESSION(sb))))
 		{
 			ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
 			location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
@@ -1258,7 +1257,7 @@
 					Uint32 pos;
 
 					pos = udf_block_map(UDF_SB_VAT(sb), 0);
-					bh = bread(sb->s_dev, pos, sb->s_blocksize);
+					bh = sb_bread(sb, pos);
 					UDF_SB_TYPEVIRT(sb,i).s_start_offset =
 						le16_to_cpu(((struct VirtualAllocationTable20 *)bh->b_data + udf_ext0_offset(UDF_SB_VAT(sb)))->lengthHeader) +
 							udf_ext0_offset(UDF_SB_VAT(sb));
@@ -1728,7 +1727,7 @@
 		{
 			udf_release_data(bh);
 			newblock = udf_get_lb_pblock(sb, loc, ++block);
-			bh = udf_tread(sb, newblock, sb->s_blocksize);
+			bh = udf_tread(sb, newblock);
 			if (!bh)
 			{
 				udf_debug("read failed\n");
diff -urN linux-2.4.18-pre6/fs/udf/symlink.c linux/fs/udf/symlink.c
--- linux-2.4.18-pre6/fs/udf/symlink.c	Mon Jun 11 19:15:27 2001
+++ linux/fs/udf/symlink.c	Wed Jan 23 15:04:33 2002
@@ -88,7 +88,7 @@
 	lock_kernel();
 	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
 	{
-		bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+		bh = udf_tread(inode->i_sb, inode->i_ino);
 
 		if (!bh)
 			goto out;
@@ -97,8 +97,7 @@
 	}
 	else
 	{
-		bh = bread(inode->i_dev, udf_block_map(inode, 0),
-				inode->i_sb->s_blocksize);
+		bh = sb_bread(inode->i_sb, udf_block_map(inode, 0));
 
 		if (!bh)
 			goto out;
diff -urN linux-2.4.18-pre6/fs/udf/udfdecl.h linux/fs/udf/udfdecl.h
--- linux-2.4.18-pre6/fs/udf/udfdecl.h	Mon Oct 15 18:49:21 2001
+++ linux/fs/udf/udfdecl.h	Wed Jan 23 15:04:33 2002
@@ -139,8 +139,8 @@
 
 /* misc.c */
 extern int udf_read_tagged_data(char *, int size, int fd, int block, int partref);
-extern struct buffer_head *udf_tgetblk(struct super_block *, int, int);
-extern struct buffer_head *udf_tread(struct super_block *, int, int);
+extern struct buffer_head *udf_tgetblk(struct super_block *, int);
+extern struct buffer_head *udf_tread(struct super_block *, int);
 extern struct GenericAttrFormat *udf_add_extendedattr(struct inode *, Uint32, Uint32, Uint8, struct buffer_head **);
 extern struct GenericAttrFormat *udf_get_extendedattr(struct inode *, Uint32, Uint8, struct buffer_head **);
 extern struct buffer_head *udf_read_tagged(struct super_block *, Uint32, Uint32, Uint16 *);
diff -urN linux-2.4.18-pre6/fs/ufs/balloc.c linux/fs/ufs/balloc.c
--- linux-2.4.18-pre6/fs/ufs/balloc.c	Wed Jan 23 15:04:30 2002
+++ linux/fs/ufs/balloc.c	Wed Jan 23 15:04:33 2002
@@ -223,7 +223,7 @@
 
 #define NULLIFY_FRAGMENTS \
 	for (i = oldcount; i < newcount; i++) { \
-		bh = getblk (sb->s_dev, result + i, sb->s_blocksize); \
+		bh = sb_getblk(sb, result + i); \
 		memset (bh->b_data, 0, sb->s_blocksize); \
 		mark_buffer_uptodate(bh, 1); \
 		mark_buffer_dirty (bh); \
@@ -357,7 +357,7 @@
 	result = ufs_alloc_fragments (inode, cgno, goal, request, err);
 	if (result) {
 		for (i = 0; i < oldcount; i++) {
-			bh = bread (sb->s_dev, tmp + i, sb->s_blocksize);
+			bh = sb_bread(sb, tmp + i);
 			if(bh)
 			{
 				mark_buffer_clean (bh);
diff -urN linux-2.4.18-pre6/fs/ufs/cylinder.c linux/fs/ufs/cylinder.c
--- linux-2.4.18-pre6/fs/ufs/cylinder.c	Mon Nov 19 14:55:46 2001
+++ linux/fs/ufs/cylinder.c	Wed Jan 23 15:04:33 2002
@@ -54,7 +54,7 @@
 	 */
 	UCPI_UBH->bh[0] = sb->u.ufs_sb.s_ucg[cgno];
 	for (i = 1; i < UCPI_UBH->count; i++)
-		if (!(UCPI_UBH->bh[i] = bread (sb->s_dev, UCPI_UBH->fragment + i, sb->s_blocksize)))
+		if (!(UCPI_UBH->bh[i] = sb_bread(sb, UCPI_UBH->fragment + i)))
 			goto failed;
 	sb->u.ufs_sb.s_cgno[bitmap_nr] = cgno;
 			
diff -urN linux-2.4.18-pre6/fs/ufs/dir.c linux/fs/ufs/dir.c
--- linux-2.4.18-pre6/fs/ufs/dir.c	Mon Nov 19 15:00:26 2001
+++ linux/fs/ufs/dir.c	Wed Jan 23 15:04:33 2002
@@ -74,7 +74,7 @@
 	while (!error && !stored && filp->f_pos < inode->i_size) {
 		lblk = (filp->f_pos) >> sb->s_blocksize_bits;
 		blk = ufs_frag_map(inode, lblk);
-		if (!blk || !(bh = bread (sb->s_dev, blk, sb->s_blocksize))) {
+		if (!blk || !(bh = sb_bread(sb, blk))) {
 			/* XXX - error - skip to the next block */
 			printk("ufs_readdir: "
 			       "dir inode %lu has a hole at offset %lu\n",
diff -urN linux-2.4.18-pre6/fs/ufs/inode.c linux/fs/ufs/inode.c
--- linux-2.4.18-pre6/fs/ufs/inode.c	Wed Jan 23 15:04:30 2002
+++ linux/fs/ufs/inode.c	Wed Jan 23 15:04:33 2002
@@ -106,8 +106,7 @@
 		struct buffer_head *bh;
 		int n = *p++;
 
-		bh = bread(sb->s_dev, uspi->s_sbbase + fs32_to_cpu(sb, block)+(n>>shift),
-				sb->s_blocksize);
+		bh = sb_bread(sb, uspi->s_sbbase + fs32_to_cpu(sb, block)+(n>>shift));
 		if (!bh)
 			goto out;
 		block = ((u32*) bh->b_data)[n & mask];
@@ -147,8 +146,7 @@
 	lastfrag = inode->u.ufs_i.i_lastfrag;
 	if (tmp && fragment < lastfrag) {
 		if (metadata) {
-			result = getblk (sb->s_dev, uspi->s_sbbase + tmp + blockoff,
-					 sb->s_blocksize);
+			result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
 			if (tmp == fs32_to_cpu(sb, *p)) {
 				UFSD(("EXIT, result %u\n", tmp + blockoff))
 				return result;
@@ -216,7 +214,7 @@
 	 * now. -DaveM
 	 */
 	if (metadata) {
-		result = getblk (inode->i_dev, tmp + blockoff, sb->s_blocksize);
+		result = sb_getblk(inode->i_sb, tmp + blockoff);
 	} else {
 		*phys = tmp;
 		result = NULL;
@@ -264,8 +262,7 @@
 	tmp = fs32_to_cpu(sb, *p);
 	if (tmp) {
 		if (metadata) {
-			result = getblk (bh->b_dev, uspi->s_sbbase + tmp + blockoff,
-					 sb->s_blocksize);
+			result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
 			if (tmp == fs32_to_cpu(sb, *p))
 				goto out;
 			brelse (result);
@@ -292,7 +289,7 @@
 	 * now. -DaveM
 	 */
 	if (metadata) {
-		result = getblk (bh->b_dev, tmp + blockoff, sb->s_blocksize);
+		result = sb_getblk(sb, tmp + blockoff);
 	} else {
 		*phys = tmp;
 		*new = 1;
@@ -425,7 +422,7 @@
 	*err = error;
 	if (!error && buffer_mapped(&dummy)) {
 		struct buffer_head *bh;
-		bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
+		bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
 		if (buffer_new(&dummy)) {
 			memset(bh->b_data, 0, inode->i_sb->s_blocksize);
 			mark_buffer_uptodate(bh, 1);
@@ -500,7 +497,7 @@
 		goto bad_inode;
 	}
 	
-	bh = bread (sb->s_dev, uspi->s_sbbase + ufs_inotofsba(inode->i_ino), sb->s_blocksize);
+	bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino));
 	if (!bh) {
 		ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino);
 		goto bad_inode;
@@ -596,7 +593,7 @@
 		return -1;
 	}
 
-	bh = bread (sb->s_dev, ufs_inotofsba(inode->i_ino), sb->s_blocksize);
+	bh = sb_bread(sb, ufs_inotofsba(inode->i_ino));
 	if (!bh) {
 		ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino);
 		return -1;
diff -urN linux-2.4.18-pre6/fs/ufs/super.c linux/fs/ufs/super.c
--- linux-2.4.18-pre6/fs/ufs/super.c	Wed Jan 23 15:04:30 2002
+++ linux/fs/ufs/super.c	Wed Jan 23 15:04:33 2002
@@ -339,7 +339,7 @@
 		size = uspi->s_bsize;
 		if (i + uspi->s_fpb > blks)
 			size = (blks - i) * uspi->s_fsize;
-		ubh = ubh_bread(sb->s_dev, uspi->s_csaddr + i, size);
+		ubh = ubh_bread(sb, uspi->s_csaddr + i, size);
 		if (!ubh)
 			goto failed;
 		ubh_ubhcpymem (space, ubh, size);
@@ -363,7 +363,7 @@
 	}
 	for (i = 0; i < uspi->s_ncg; i++) {
 		UFSD(("read cg %u\n", i))
-		if (!(sb->u.ufs_sb.s_ucg[i] = bread (sb->s_dev, ufs_cgcmin(i), sb->s_blocksize)))
+		if (!(sb->u.ufs_sb.s_ucg[i] = sb_bread(sb, ufs_cgcmin(i))))
 			goto failed;
 		if (!ufs_cg_chkmagic (sb, (struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data))
 			goto failed;
@@ -414,7 +414,7 @@
 		size = uspi->s_bsize;
 		if (i + uspi->s_fpb > blks)
 			size = (blks - i) * uspi->s_fsize;
-		ubh = ubh_bread (sb->s_dev, uspi->s_csaddr + i, size);
+		ubh = ubh_bread(sb, uspi->s_csaddr + i, size);
 		ubh_memcpyubh (ubh, space, size);
 		space += size;
 		ubh_mark_buffer_uptodate (ubh, 1);
@@ -598,11 +598,12 @@
 	
 again:	
 	set_blocksize (sb->s_dev, block_size);
+	sb->s_blocksize = block_size;
 
 	/*
 	 * read ufs super block from device
 	 */
-	ubh = ubh_bread_uspi (uspi, sb->s_dev, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size);
+	ubh = ubh_bread_uspi (uspi, sb, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size);
 	if (!ubh) 
 		goto failed;
 	
diff -urN linux-2.4.18-pre6/fs/ufs/truncate.c linux/fs/ufs/truncate.c
--- linux-2.4.18-pre6/fs/ufs/truncate.c	Mon Nov 19 14:55:46 2001
+++ linux/fs/ufs/truncate.c	Wed Jan 23 15:04:33 2002
@@ -114,7 +114,7 @@
 	frag1 = ufs_fragnum (frag1);
 	frag2 = ufs_fragnum (frag2);
 	for (j = frag1; j < frag2; j++) {
-		bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize);
+		bh = sb_get_hash_table (sb, tmp + j);
 		if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *p)) {
 			retry = 1;
 			brelse (bh);
@@ -137,7 +137,7 @@
 		if (!tmp)
 			continue;
 		for (j = 0; j < uspi->s_fpb; j++) {
-			bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize);
+			bh = sb_get_hash_table(sb, tmp + j);
 			if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *p)) {
 				retry = 1;
 				brelse (bh);
@@ -176,7 +176,7 @@
 		ufs_panic(sb, "ufs_truncate_direct", "internal error");
 	frag4 = ufs_fragnum (frag4);
 	for (j = 0; j < frag4; j++) {
-		bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize);
+		bh = sb_get_hash_table (sb, tmp + j);
 		if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *p)) {
 			retry = 1;
 			brelse (bh);
@@ -218,7 +218,7 @@
 	tmp = fs32_to_cpu(sb, *p);
 	if (!tmp)
 		return 0;
-	ind_ubh = ubh_bread (sb->s_dev, tmp, uspi->s_bsize);
+	ind_ubh = ubh_bread(sb, tmp, uspi->s_bsize);
 	if (tmp != fs32_to_cpu(sb, *p)) {
 		ubh_brelse (ind_ubh);
 		return 1;
@@ -235,7 +235,7 @@
 		if (!tmp)
 			continue;
 		for (j = 0; j < uspi->s_fpb; j++) {
-			bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize);
+			bh = sb_get_hash_table(sb, tmp + j);
 			if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *ind)) {
 				retry = 1;
 				brelse (bh);
@@ -312,7 +312,7 @@
 	tmp = fs32_to_cpu(sb, *p);
 	if (!tmp)
 		return 0;
-	dind_bh = ubh_bread (inode->i_dev, tmp, uspi->s_bsize);
+	dind_bh = ubh_bread(sb, tmp, uspi->s_bsize);
 	if (tmp != fs32_to_cpu(sb, *p)) {
 		ubh_brelse (dind_bh);
 		return 1;
@@ -378,7 +378,7 @@
 	p = inode->u.ufs_i.i_u1.i_data + UFS_TIND_BLOCK;
 	if (!(tmp = fs32_to_cpu(sb, *p)))
 		return 0;
-	tind_bh = ubh_bread (sb->s_dev, tmp, uspi->s_bsize);
+	tind_bh = ubh_bread (sb, tmp, uspi->s_bsize);
 	if (tmp != fs32_to_cpu(sb, *p)) {
 		ubh_brelse (tind_bh);
 		return 1;
diff -urN linux-2.4.18-pre6/fs/ufs/util.c linux/fs/ufs/util.c
--- linux-2.4.18-pre6/fs/ufs/util.c	Mon Sep 10 09:04:53 2001
+++ linux/fs/ufs/util.c	Wed Jan 23 15:04:33 2002
@@ -23,7 +23,7 @@
 
 
 struct ufs_buffer_head * _ubh_bread_ (struct ufs_sb_private_info * uspi,
-	kdev_t dev, unsigned fragment, unsigned size)
+	struct super_block *sb, unsigned fragment, unsigned size)
 {
 	struct ufs_buffer_head * ubh;
 	unsigned i, j, count;
@@ -39,7 +39,7 @@
 	ubh->fragment = fragment;
 	ubh->count = count;
 	for (i = 0; i < count; i++)
-		if (!(ubh->bh[i] = bread (dev, fragment + i, uspi->s_fsize)))
+		if (!(ubh->bh[i] = sb_bread(sb, fragment + i)))
 			goto failed;
 	for (; i < UFS_MAXFRAG; i++)
 		ubh->bh[i] = NULL;
@@ -51,7 +51,7 @@
 }
 
 struct ufs_buffer_head * ubh_bread_uspi (struct ufs_sb_private_info * uspi,
-	kdev_t dev, unsigned fragment, unsigned size)
+	struct super_block *sb, unsigned fragment, unsigned size)
 {
 	unsigned i, j, count;
 	if (size & ~uspi->s_fmask)
@@ -62,7 +62,7 @@
 	USPI_UBH->fragment = fragment;
 	USPI_UBH->count = count;
 	for (i = 0; i < count; i++)
-		if (!(USPI_UBH->bh[i] = bread (dev, fragment + i, uspi->s_fsize)))
+		if (!(USPI_UBH->bh[i] = sb_bread(sb, fragment + i)))
 			goto failed;
 	for (; i < UFS_MAXFRAG; i++)
 		USPI_UBH->bh[i] = NULL;
diff -urN linux-2.4.18-pre6/fs/ufs/util.h linux/fs/ufs/util.h
--- linux-2.4.18-pre6/fs/ufs/util.h	Mon Nov 19 15:25:45 2001
+++ linux/fs/ufs/util.h	Wed Jan 23 15:04:33 2002
@@ -226,9 +226,9 @@
 /*
  * These functions manipulate ufs buffers
  */
-#define ubh_bread(dev,fragment,size) _ubh_bread_(uspi,dev,fragment,size)  
-extern struct ufs_buffer_head * _ubh_bread_(struct ufs_sb_private_info *, kdev_t, unsigned, unsigned);
-extern struct ufs_buffer_head * ubh_bread_uspi(struct ufs_sb_private_info *, kdev_t, unsigned, unsigned);
+#define ubh_bread(sb,fragment,size) _ubh_bread_(uspi,sb,fragment,size)  
+extern struct ufs_buffer_head * _ubh_bread_(struct ufs_sb_private_info *, struct super_block *, unsigned, unsigned);
+extern struct ufs_buffer_head * ubh_bread_uspi(struct ufs_sb_private_info *, struct super_block *, unsigned, unsigned);
 extern void ubh_brelse (struct ufs_buffer_head *);
 extern void ubh_brelse_uspi (struct ufs_sb_private_info *);
 extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *);
diff -urN linux-2.4.18-pre6/include/asm-i386/timex.h linux/include/asm-i386/timex.h
--- linux-2.4.18-pre6/include/asm-i386/timex.h	Thu Nov 22 11:46:18 2001
+++ linux/include/asm-i386/timex.h	Wed Jan 23 15:04:33 2002
@@ -9,7 +9,12 @@
 #include <linux/config.h>
 #include <asm/msr.h>
 
-#define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
+#ifdef CONFIG_MELAN
+#  define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
+#else
+#  define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
+#endif
+
 #define CLOCK_TICK_FACTOR	20	/* Factor of both 1000000 and CLOCK_TICK_RATE */
 #define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
 	(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
diff -urN linux-2.4.18-pre6/include/linux/amigaffs.h linux/include/linux/amigaffs.h
--- linux-2.4.18-pre6/include/linux/amigaffs.h	Tue Sep 11 08:20:30 2001
+++ linux/include/linux/amigaffs.h	Wed Jan 23 15:04:33 2002
@@ -31,7 +31,7 @@
 {
 	pr_debug(KERN_DEBUG "affs_bread: %d\n", block);
 	if (block >= AFFS_SB->s_reserved && block < AFFS_SB->s_partition_size)
-		return bread(sb->s_dev, block, sb->s_blocksize);
+		return sb_bread(sb, block);
 	return NULL;
 }
 static inline struct buffer_head *
@@ -39,7 +39,7 @@
 {
 	pr_debug(KERN_DEBUG "affs_getblk: %d\n", block);
 	if (block >= AFFS_SB->s_reserved && block < AFFS_SB->s_partition_size)
-		return getblk(sb->s_dev, block, sb->s_blocksize);
+		return sb_getblk(sb, block);
 	return NULL;
 }
 static inline struct buffer_head *
@@ -48,10 +48,11 @@
 	struct buffer_head *bh;
 	pr_debug(KERN_DEBUG "affs_getzeroblk: %d\n", block);
 	if (block >= AFFS_SB->s_reserved && block < AFFS_SB->s_partition_size) {
-		bh = getblk(sb->s_dev, block, sb->s_blocksize);
-		wait_on_buffer(bh);
+		bh = sb_getblk(sb, block);
+		lock_buffer(bh);
 		memset(bh->b_data, 0 , sb->s_blocksize);
 		mark_buffer_uptodate(bh, 1);
+		unlock_buffer(bh);
 		return bh;
 	}
 	return NULL;
@@ -62,7 +63,7 @@
 	struct buffer_head *bh;
 	pr_debug(KERN_DEBUG "affs_getemptyblk: %d\n", block);
 	if (block >= AFFS_SB->s_reserved && block < AFFS_SB->s_partition_size) {
-		bh = getblk(sb->s_dev, block, sb->s_blocksize);
+		bh = sb_getblk(sb, block);
 		wait_on_buffer(bh);
 		mark_buffer_uptodate(bh, 1);
 		return bh;
diff -urN linux-2.4.18-pre6/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.4.18-pre6/include/linux/fs.h	Wed Jan 23 15:04:30 2002
+++ linux/include/linux/fs.h	Wed Jan 23 15:04:33 2002
@@ -108,6 +108,7 @@
 #define MS_NOATIME	1024	/* Do not update access times. */
 #define MS_NODIRATIME	2048	/* Do not update directory access times */
 #define MS_BIND		4096
+#define MS_MOVE		8192
 #define MS_REC		16384
 #define MS_VERBOSE	32768
 #define MS_ACTIVE	(1<<30)
@@ -1365,6 +1366,18 @@
 }
 extern int set_blocksize(kdev_t, int);
 extern struct buffer_head * bread(kdev_t, int, int);
+static inline struct buffer_head * sb_bread(struct super_block *sb, int block)
+{
+	return bread(sb->s_dev, block, sb->s_blocksize);
+}
+static inline struct buffer_head * sb_getblk(struct super_block *sb, int block)
+{
+	return getblk(sb->s_dev, block, sb->s_blocksize);
+}
+static inline struct buffer_head * sb_get_hash_table(struct super_block *sb, int block)
+{
+	return get_hash_table(sb->s_dev, block, sb->s_blocksize);
+}
 extern void wakeup_bdflush(void);
 extern void put_unused_buffer_head(struct buffer_head * bh);
 extern struct buffer_head * get_unused_buffer_head(int async);
@@ -1392,8 +1405,9 @@
 int generic_commit_write(struct file *, struct page *, unsigned, unsigned);
 int block_truncate_page(struct address_space *, loff_t, get_block_t *);
 extern int generic_direct_IO(int, struct inode *, struct kiobuf *, unsigned long, int, get_block_t *);
+extern int waitfor_one_page(struct page *);
+extern int writeout_one_page(struct page *);
 
-extern int waitfor_one_page(struct page*);
 extern int generic_file_mmap(struct file *, struct vm_area_struct *);
 extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
 extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
diff -urN linux-2.4.18-pre6/include/linux/iso_fs.h linux/include/linux/iso_fs.h
--- linux-2.4.18-pre6/include/linux/iso_fs.h	Thu Nov 22 11:47:11 2001
+++ linux/include/linux/iso_fs.h	Wed Jan 23 15:04:33 2002
@@ -219,7 +219,7 @@
 int get_acorn_filename(struct iso_directory_record *, char *, struct inode *);
 
 extern struct dentry *isofs_lookup(struct inode *, struct dentry *);
-extern struct buffer_head *isofs_bread(struct inode *, unsigned int, unsigned int);
+extern struct buffer_head *isofs_bread(struct inode *inode, unsigned int block);
 extern int isofs_get_blocks(struct inode *, long, struct buffer_head **, unsigned long);
 
 extern struct inode_operations isofs_dir_inode_operations;
@@ -230,11 +230,11 @@
 #ifdef LEAK_CHECK
 #define free_s leak_check_free_s
 #define malloc leak_check_malloc
-#define bread leak_check_bread
+#define sb_bread leak_check_bread
 #define brelse leak_check_brelse
 extern void * leak_check_malloc(unsigned int size);
 extern void leak_check_free_s(void * obj, int size);
-extern struct buffer_head * leak_check_bread(int dev, int block, int size);
+extern struct buffer_head * leak_check_bread(struct super_block *sb, int block);
 extern void leak_check_brelse(struct buffer_head * bh);
 #endif /* LEAK_CHECK */
 
diff -urN linux-2.4.18-pre6/include/linux/limits.h linux/include/linux/limits.h
--- linux-2.4.18-pre6/include/linux/limits.h	Wed Jul 28 10:30:10 1999
+++ linux/include/linux/limits.h	Wed Jan 23 15:04:33 2002
@@ -11,7 +11,7 @@
 #define MAX_CANON        255	/* size of the canonical input queue */
 #define MAX_INPUT        255	/* size of the type-ahead buffer */
 #define NAME_MAX         255	/* # chars in a file name */
-#define PATH_MAX        4095	/* # chars in a path name */
+#define PATH_MAX        4096	/* # chars in a path name including nul */
 #define PIPE_BUF        4096	/* # bytes in atomic write to a pipe */
 
 #define RTSIG_MAX	  32
diff -urN linux-2.4.18-pre6/include/linux/netfilter_ipv4/ip_tables.h linux/include/linux/netfilter_ipv4/ip_tables.h
--- linux-2.4.18-pre6/include/linux/netfilter_ipv4/ip_tables.h	Thu Jul 26 13:58:46 2001
+++ linux/include/linux/netfilter_ipv4/ip_tables.h	Wed Jan 23 15:04:33 2002
@@ -428,6 +428,9 @@
 
 	/* Man behind the curtain... */
 	struct ipt_table_info *private;
+
+	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
+	struct module *me;
 };
 
 extern int ipt_register_table(struct ipt_table *table);
diff -urN linux-2.4.18-pre6/include/linux/netfilter_ipv6/ip6_tables.h linux/include/linux/netfilter_ipv6/ip6_tables.h
--- linux-2.4.18-pre6/include/linux/netfilter_ipv6/ip6_tables.h	Thu Jul 26 13:59:06 2001
+++ linux/include/linux/netfilter_ipv6/ip6_tables.h	Wed Jan 23 15:04:33 2002
@@ -435,6 +435,9 @@
 
 	/* Man behind the curtain... */
 	struct ip6t_table_info *private;
+
+	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
+	struct module *me;
 };
 
 extern int ip6t_register_table(struct ip6t_table *table);
diff -urN linux-2.4.18-pre6/include/linux/netlink.h linux/include/linux/netlink.h
--- linux-2.4.18-pre6/include/linux/netlink.h	Fri Dec 21 09:42:03 2001
+++ linux/include/linux/netlink.h	Wed Jan 23 15:04:33 2002
@@ -6,6 +6,7 @@
 #define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
 #define NETLINK_FIREWALL	3	/* Firewalling hook				*/
 #define NETLINK_TCPDIAG		4	/* TCP socket monitoring			*/
+#define NETLINK_NFLOG		5	/* netfilter/iptables ULOG */
 #define NETLINK_ARPD		8
 #define NETLINK_ROUTE6		11	/* af_inet6 route comm channel */
 #define NETLINK_IP6_FW		13
diff -urN linux-2.4.18-pre6/include/linux/prctl.h linux/include/linux/prctl.h
--- linux-2.4.18-pre6/include/linux/prctl.h	Thu Jul 19 20:39:57 2001
+++ linux/include/linux/prctl.h	Wed Jan 23 15:04:33 2002
@@ -20,4 +20,10 @@
 #define PR_GET_KEEPCAPS   7
 #define PR_SET_KEEPCAPS   8
 
+/* Get/set floating-point emulation control bits (if meaningful) */
+#define PR_GET_FPEMU  9
+#define PR_SET_FPEMU 10
+# define PR_FPEMU_NOPRINT	1	/* silently emulate fp operations accesses */
+# define PR_FPEMU_SIGFPE	2	/* don't emulate fp operations, send SIGFPE instead */
+
 #endif /* _LINUX_PRCTL_H */
diff -urN linux-2.4.18-pre6/include/linux/rtnetlink.h linux/include/linux/rtnetlink.h
--- linux-2.4.18-pre6/include/linux/rtnetlink.h	Fri Dec 21 09:42:03 2001
+++ linux/include/linux/rtnetlink.h	Wed Jan 23 15:04:33 2002
@@ -586,9 +586,9 @@
 extern void rtnetlink_init(void);
 
 #define ASSERT_RTNL() do { if (down_trylock(&rtnl_sem) == 0)  { up(&rtnl_sem); \
-printk("RTNL: assertion failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } \
+printk("RTNL: assertion failed at " __FILE__ "(%d)\n", __LINE__); } \
 		   } while(0);
-#define BUG_TRAP(x) if (!(x)) { printk("KERNEL: assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); }
+#define BUG_TRAP(x) if (!(x)) { printk("KERNEL: assertion (" #x ") failed at " __FILE__ "(%d)\n", __LINE__); }
 
 
 #endif /* __KERNEL__ */
diff -urN linux-2.4.18-pre6/include/net/inetpeer.h linux/include/net/inetpeer.h
--- linux-2.4.18-pre6/include/net/inetpeer.h	Thu Nov 22 11:47:11 2001
+++ linux/include/net/inetpeer.h	Wed Jan 23 15:04:33 2002
@@ -1,7 +1,7 @@
 /*
  *		INETPEER - A storage for permanent information about peers
  *
- *  Version:	$Id: inetpeer.h,v 1.1 2000/01/06 00:41:51 davem Exp $
+ *  Version:	$Id: inetpeer.h,v 1.1.2.1 2002/01/12 07:53:15 davem Exp $
  *
  *  Authors:	Andrey V. Savochkin <saw@msu.ru>
  */
@@ -38,7 +38,7 @@
 extern struct inet_peer *inet_peer_unused_head;
 extern struct inet_peer **inet_peer_unused_tailp;
 /* can be called from BH context or outside */
-extern inline void	inet_putpeer(struct inet_peer *p)
+static inline void	inet_putpeer(struct inet_peer *p)
 {
 	spin_lock_bh(&inet_peer_unused_lock);
 	if (atomic_dec_and_test(&p->refcnt)) {
@@ -53,7 +53,7 @@
 
 extern spinlock_t inet_peer_idlock;
 /* can be called with or without local BH being disabled */
-extern inline __u16	inet_getid(struct inet_peer *p)
+static inline __u16	inet_getid(struct inet_peer *p)
 {
 	__u16 id;
 
diff -urN linux-2.4.18-pre6/init/main.c linux/init/main.c
--- linux-2.4.18-pre6/init/main.c	Fri Dec 21 09:42:04 2001
+++ linux/init/main.c	Wed Jan 23 15:04:33 2002
@@ -106,6 +106,9 @@
 #if defined(CONFIG_SYSVIPC)
 extern void ipc_init(void);
 #endif
+#ifdef CONFIG_PERFMON
+extern void perfmon_init(void);
+#endif
 
 /*
  * Boot command-line arguments
@@ -593,6 +596,9 @@
 	kmem_cache_sizes_init();
 	pgtable_cache_init();
 
+#ifdef CONFIG_PERFMON
+	perfmon_init();
+#endif
 	mempages = num_physpages;
 
 	fork_init(mempages);
diff -urN linux-2.4.18-pre6/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-2.4.18-pre6/kernel/ksyms.c	Wed Jan 23 15:04:30 2002
+++ linux/kernel/ksyms.c	Wed Jan 23 15:04:33 2002
@@ -353,7 +353,9 @@
 EXPORT_SYMBOL(del_timer);
 EXPORT_SYMBOL(request_irq);
 EXPORT_SYMBOL(free_irq);
+#if !defined(CONFIG_IA64)	/* irq_stat is part of struct cpuinfo_ia64 */
 EXPORT_SYMBOL(irq_stat);
+#endif
 
 /* waitqueue handling */
 EXPORT_SYMBOL(add_wait_queue);
diff -urN linux-2.4.18-pre6/kernel/sys.c linux/kernel/sys.c
--- linux-2.4.18-pre6/kernel/sys.c	Tue Sep 18 14:10:43 2001
+++ linux/kernel/sys.c	Wed Jan 23 15:04:33 2002
@@ -1245,6 +1245,22 @@
 #endif
 			break;
 
+	        case PR_SET_FPEMU:
+#ifdef SET_FPEMU_CTL
+			error = SET_FPEMU_CTL(current, arg2);
+#else
+			error = -EINVAL;
+#endif
+			break;
+
+	        case PR_GET_FPEMU:
+#ifdef GET_FPEMU_CTL
+			error = GET_FPEMU_CTL(current, arg2);
+#else
+			error = -EINVAL;
+#endif
+			break;
+
 		case PR_GET_KEEPCAPS:
 			if (current->keep_capabilities)
 				error = 1;
diff -urN linux-2.4.18-pre6/mm/filemap.c linux/mm/filemap.c
--- linux-2.4.18-pre6/mm/filemap.c	Wed Jan 23 15:04:30 2002
+++ linux/mm/filemap.c	Wed Jan 23 15:04:33 2002
@@ -454,41 +454,6 @@
 	return page;
 }
 
-/*
- * By the time this is called, the page is locked and
- * we don't have to worry about any races any more.
- *
- * Start the IO..
- */
-static int writeout_one_page(struct page *page)
-{
-	struct buffer_head *bh, *head = page->buffers;
-
-	bh = head;
-	do {
-		if (buffer_locked(bh) || !buffer_dirty(bh) || !buffer_uptodate(bh))
-			continue;
-
-		bh->b_flushtime = jiffies;
-		ll_rw_block(WRITE, 1, &bh);	
-	} while ((bh = bh->b_this_page) != head);
-	return 0;
-}
-
-int waitfor_one_page(struct page *page)
-{
-	int error = 0;
-	struct buffer_head *bh, *head = page->buffers;
-
-	bh = head;
-	do {
-		wait_on_buffer(bh);
-		if (buffer_req(bh) && !buffer_uptodate(bh))
-			error = -EIO;
-	} while ((bh = bh->b_this_page) != head);
-	return error;
-}
-
 static int do_buffer_fdatasync(struct list_head *head, unsigned long start, unsigned long end, int (*fn)(struct page *))
 {
 	struct list_head *curr;
diff -urN linux-2.4.18-pre6/net/core/rtnetlink.c linux/net/core/rtnetlink.c
--- linux-2.4.18-pre6/net/core/rtnetlink.c	Fri Dec 21 09:42:05 2001
+++ linux/net/core/rtnetlink.c	Wed Jan 23 15:04:33 2002
@@ -45,7 +45,6 @@
 #include <net/protocol.h>
 #include <net/arp.h>
 #include <net/route.h>
-#include <net/tcp.h>
 #include <net/udp.h>
 #include <net/sock.h>
 #include <net/pkt_sched.h>
diff -urN linux-2.4.18-pre6/net/ipv4/fib_semantics.c linux/net/ipv4/fib_semantics.c
--- linux-2.4.18-pre6/net/ipv4/fib_semantics.c	Fri Dec 21 09:42:05 2001
+++ linux/net/ipv4/fib_semantics.c	Wed Jan 23 15:04:33 2002
@@ -5,7 +5,7 @@
  *
  *		IPv4 Forwarding Information Base: semantics.
  *
- * Version:	$Id: fib_semantics.c,v 1.18 2001/10/31 21:55:54 davem Exp $
+ * Version:	$Id: fib_semantics.c,v 1.18.2.2 2002/01/12 07:54:15 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -134,7 +134,7 @@
 	write_unlock(&fib_info_lock);
 }
 
-extern __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
+static __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
 {
 	const struct fib_nh *onh = ofi->fib_nh;
 
@@ -155,7 +155,7 @@
 	return 0;
 }
 
-extern __inline__ struct fib_info * fib_find_info(const struct fib_info *nfi)
+static __inline__ struct fib_info * fib_find_info(const struct fib_info *nfi)
 {
 	for_fib_info() {
 		if (fi->fib_nhs != nfi->fib_nhs)
diff -urN linux-2.4.18-pre6/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- linux-2.4.18-pre6/net/ipv4/ip_fragment.c	Fri Sep  7 11:01:21 2001
+++ linux/net/ipv4/ip_fragment.c	Wed Jan 23 15:04:33 2002
@@ -5,7 +5,7 @@
  *
  *		The IP fragmentation functionality.
  *		
- * Version:	$Id: ip_fragment.c,v 1.58 2001/09/01 00:31:50 davem Exp $
+ * Version:	$Id: ip_fragment.c,v 1.58.2.1 2002/01/12 07:53:15 davem Exp $
  *
  * Authors:	Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
  *		Alan Cox <Alan.Cox@linux.org>
@@ -130,19 +130,19 @@
 atomic_t ip_frag_mem = ATOMIC_INIT(0);	/* Memory used for fragments */
 
 /* Memory Tracking Functions. */
-extern __inline__ void frag_kfree_skb(struct sk_buff *skb)
+static __inline__ void frag_kfree_skb(struct sk_buff *skb)
 {
 	atomic_sub(skb->truesize, &ip_frag_mem);
 	kfree_skb(skb);
 }
 
-extern __inline__ void frag_free_queue(struct ipq *qp)
+static __inline__ void frag_free_queue(struct ipq *qp)
 {
 	atomic_sub(sizeof(struct ipq), &ip_frag_mem);
 	kfree(qp);
 }
 
-extern __inline__ struct ipq *frag_alloc_queue(void)
+static __inline__ struct ipq *frag_alloc_queue(void)
 {
 	struct ipq *qp = kmalloc(sizeof(struct ipq), GFP_ATOMIC);
 
diff -urN linux-2.4.18-pre6/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c
--- linux-2.4.18-pre6/net/ipv4/ip_input.c	Wed Nov  7 14:39:36 2001
+++ linux/net/ipv4/ip_input.c	Wed Jan 23 15:04:33 2002
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) module.
  *
- * Version:	$Id: ip_input.c,v 1.54 2001/11/06 22:33:52 davem Exp $
+ * Version:	$Id: ip_input.c,v 1.54.2.1 2002/01/12 07:39:23 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -224,8 +224,7 @@
 	nf_debug_ip_local_deliver(skb);
 #endif /*CONFIG_NETFILTER_DEBUG*/
 
-	/* Pull out additionl 8 bytes to save some space in protocols. */
-	if (!pskb_may_pull(skb, ihl+8))
+	if (!pskb_may_pull(skb, ihl))
 		goto out;
 	__skb_pull(skb, ihl);
 
diff -urN linux-2.4.18-pre6/net/ipv4/netfilter/Config.in linux/net/ipv4/netfilter/Config.in
--- linux-2.4.18-pre6/net/ipv4/netfilter/Config.in	Fri Dec 21 09:42:05 2001
+++ linux/net/ipv4/netfilter/Config.in	Wed Jan 23 15:04:33 2002
@@ -21,6 +21,7 @@
   dep_tristate '  netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
   dep_tristate '  Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
+  dep_tristate '  AH/ESP match support' CONFIG_IP_NF_MATCH_AH_ESP $CONFIG_IP_NF_IPTABLES
   dep_tristate '  LENGTH match support' CONFIG_IP_NF_MATCH_LENGTH $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TTL match support' CONFIG_IP_NF_MATCH_TTL $CONFIG_IP_NF_IPTABLES
   dep_tristate '  tcpmss match support' CONFIG_IP_NF_MATCH_TCPMSS $CONFIG_IP_NF_IPTABLES
@@ -74,6 +75,9 @@
     dep_tristate '    MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
   fi
   dep_tristate '  LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
+  if [ "$CONFIG_NETLINK" != "n" ]; then
+     dep_tristate '  ULOG target support' CONFIG_IP_NF_TARGET_ULOG $CONFIG_NETLINK $CONFIG_IP_NF_IPTABLES
+  fi
   dep_tristate '  TCPMSS target support' CONFIG_IP_NF_TARGET_TCPMSS $CONFIG_IP_NF_IPTABLES
 fi
 
diff -urN linux-2.4.18-pre6/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
--- linux-2.4.18-pre6/net/ipv4/netfilter/Makefile	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv4/netfilter/Makefile	Wed Jan 23 15:04:33 2002
@@ -56,6 +56,7 @@
 obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
+obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
 
 obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
 
@@ -73,6 +74,7 @@
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
 obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
 obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
+obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
 obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
 
 # backwards compatibility 
diff -urN linux-2.4.18-pre6/net/ipv4/netfilter/ip_fw_compat_masq.c linux/net/ipv4/netfilter/ip_fw_compat_masq.c
--- linux-2.4.18-pre6/net/ipv4/netfilter/ip_fw_compat_masq.c	Fri Sep 14 14:04:08 2001
+++ linux/net/ipv4/netfilter/ip_fw_compat_masq.c	Wed Jan 23 15:04:33 2002
@@ -157,7 +157,7 @@
 		/* Fall thru... */
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
-		IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
+		IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
 
 		if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) {
 			if (net_ratelimit())
diff -urN linux-2.4.18-pre6/net/ipv4/netfilter/ip_fw_compat_redir.c linux/net/ipv4/netfilter/ip_fw_compat_redir.c
--- linux-2.4.18-pre6/net/ipv4/netfilter/ip_fw_compat_redir.c	Fri Dec 21 09:42:05 2001
+++ linux/net/ipv4/netfilter/ip_fw_compat_redir.c	Wed Jan 23 15:04:33 2002
@@ -20,6 +20,9 @@
 
 #include <linux/netfilter_ipv4/lockhelp.h>
 
+/* Very simple timeout pushed back by each packet */
+#define REDIR_TIMEOUT (240*HZ)
+
 static DECLARE_LOCK(redir_lock);
 #define ASSERT_READ_LOCK(x) MUST_BE_LOCKED(&redir_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_LOCKED(&redir_lock)
@@ -150,6 +153,14 @@
 	skb->nfcache |= NFC_ALTERED;
 }
 
+static void destroyme(unsigned long me)
+{
+	LOCK_BH(&redir_lock);
+	LIST_DELETE(&redirs, (struct redir *)me);
+	UNLOCK_BH(&redir_lock);
+	kfree((struct redir *)me);
+}
+
 /* REDIRECT a packet. */
 unsigned int
 do_redirect(struct sk_buff *skb,
@@ -172,6 +183,10 @@
 		struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph
 							+ iph->ihl);
 
+		/* Must have whole header */
+		if (skb->len < iph->ihl*4 + sizeof(*udph))
+			return NF_DROP;
+
 		if (udph->check) /* 0 is a special case meaning no checksum */
 			udph->check = cheat_check(~iph->daddr, newdst,
 					  cheat_check(udph->dest ^ 0xFFFF,
@@ -191,6 +206,10 @@
 		struct redir *redir;
 		int ret;
 
+		/* Must have whole header */
+		if (skb->len < iph->ihl*4 + sizeof(*tcph))
+			return NF_DROP;
+
 		DEBUGP("Doing tcp redirect. %08X:%u %08X:%u -> %08X:%u\n",
 		       iph->saddr, tcph->source, iph->daddr, tcph->dest,
 		       newdst, redirpt);
@@ -206,7 +225,9 @@
 			}
 			list_prepend(&redirs, redir);
 			init_timer(&redir->destroyme);
-			redir->destroyme.expires = jiffies + 75*HZ;
+			redir->destroyme.function = destroyme;
+			redir->destroyme.data = (unsigned long)redir;
+			redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
 			add_timer(&redir->destroyme);
 		}
 		/* In case mangling has changed, rewrite this part. */
@@ -227,13 +248,6 @@
 	}
 }
 
-static void destroyme(unsigned long me)
-{
-	LOCK_BH(&redir_lock);
-	LIST_DELETE(&redirs, (struct redir *)me);
-	UNLOCK_BH(&redir_lock);
-}
-
 /* Incoming packet: is it a reply to a masqueraded connection, or
    part of an already-redirected TCP connection? */
 void
@@ -247,15 +261,18 @@
 	if (iph->protocol != IPPROTO_TCP)
 		return;
 
+	/* Must have whole header */
+	if (skb->len < iph->ihl*4 + sizeof(*tcph))
+		return;
+
 	LOCK_BH(&redir_lock);
 	redir = find_redir(iph->saddr, iph->daddr, tcph->source, tcph->dest);
 	if (redir) {
 		DEBUGP("Doing tcp redirect again.\n");
 		do_tcp_redir(skb, redir);
-		if (tcph->rst || tcph->fin) {
-			redir->destroyme.function = destroyme;
-			redir->destroyme.data = (unsigned long)redir;
-			mod_timer(&redir->destroyme, 75*HZ);
+		if (del_timer(&redir->destroyme)) {
+			redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
+			add_timer(&redir->destroyme);
 		}
 	}
 	UNLOCK_BH(&redir_lock);
@@ -272,15 +289,18 @@
 	if (iph->protocol != IPPROTO_TCP)
 		return;
 
+	/* Must have whole header */
+	if (skb->len < iph->ihl*4 + sizeof(*tcph))
+		return;
+
 	LOCK_BH(&redir_lock);
 	redir = find_unredir(iph->saddr, iph->daddr, tcph->source, tcph->dest);
 	if (redir) {
 		DEBUGP("Doing tcp unredirect.\n");
 		do_tcp_unredir(skb, redir);
-		if (tcph->rst || tcph->fin) {
-			redir->destroyme.function = destroyme;
-			redir->destroyme.data = (unsigned long)redir;
-			mod_timer(&redir->destroyme, 75*HZ);
+		if (del_timer(&redir->destroyme)) {
+			redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
+			add_timer(&redir->destroyme);
 		}
 	}
 	UNLOCK_BH(&redir_lock);
diff -urN linux-2.4.18-pre6/net/ipv4/netfilter/ip_nat_rule.c linux/net/ipv4/netfilter/ip_nat_rule.c
--- linux-2.4.18-pre6/net/ipv4/netfilter/ip_nat_rule.c	Fri Apr 27 14:15:01 2001
+++ linux/net/ipv4/netfilter/ip_nat_rule.c	Wed Jan 23 15:04:33 2002
@@ -104,7 +104,7 @@
 
 static struct ipt_table nat_table
 = { { NULL, NULL }, "nat", &nat_initial_table.repl,
-    NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 LIST_HEAD(nat_expect_list);
 
diff -urN linux-2.4.18-pre6/net/ipv4/netfilter/ip_nat_standalone.c linux/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.4.18-pre6/net/ipv4/netfilter/ip_nat_standalone.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/ip_nat_standalone.c	Wed Jan 23 15:04:33 2002
@@ -166,19 +166,16 @@
 	return ip_nat_fn(hooknum, pskb, in, out, okfn);
 }
 
-/* FIXME: change in oif may mean change in hh_len.  Check and realloc
-   --RR */
-static int
-route_me_harder(struct sk_buff *skb)
+static int route_me_harder(struct sk_buff **pskb)
 {
-	struct iphdr *iph = skb->nh.iph;
+	struct iphdr *iph = (*pskb)->nh.iph;
 	struct rtable *rt;
 	struct rt_key key = { dst:iph->daddr,
 			      src:iph->saddr,
-			      oif:skb->sk ? skb->sk->bound_dev_if : 0,
+			      oif:(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
 			      tos:RT_TOS(iph->tos)|RTO_CONN,
 #ifdef CONFIG_IP_ROUTE_FWMARK
-			      fwmark:skb->nfmark
+			      fwmark:(*pskb)->nfmark
 #endif
 			    };
 
@@ -188,9 +185,24 @@
 	}
 
 	/* Drop old route. */
-	dst_release(skb->dst);
+	dst_release((*pskb)->dst);
 
-	skb->dst = &rt->u.dst;
+	(*pskb)->dst = &rt->u.dst;
+
+	/* Change in oif may mean change in hh_len. */
+	if (skb_headroom(*pskb) < (*pskb)->dst->dev->hard_header_len) {
+		struct sk_buff *nskb;
+
+		nskb = skb_realloc_headroom(*pskb,
+					    (*pskb)->dst->dev
+					    ->hard_header_len);
+		if (!nskb)
+			return -ENOMEM;
+		if ((*pskb)->sk)
+			skb_set_owner_w(nskb, (*pskb)->sk);
+		kfree_skb(*pskb);
+		*pskb = nskb;
+	}
 	return 0;
 }
 
@@ -216,7 +228,7 @@
 	if (ret != NF_DROP && ret != NF_STOLEN
 	    && ((*pskb)->nh.iph->saddr != saddr
 		|| (*pskb)->nh.iph->daddr != daddr))
-		return route_me_harder(*pskb) == 0 ? ret : NF_DROP;
+		return route_me_harder(pskb) == 0 ? ret : NF_DROP;
 	return ret;
 }
 
diff -urN linux-2.4.18-pre6/net/ipv4/netfilter/ip_tables.c linux/net/ipv4/netfilter/ip_tables.c
--- linux-2.4.18-pre6/net/ipv4/netfilter/ip_tables.c	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv4/netfilter/ip_tables.c	Wed Jan 23 15:04:33 2002
@@ -2,6 +2,11 @@
  * Packet matching code.
  *
  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2009-2002 Netfilter core team <coreteam@netfilter.org>
+ *
+ * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
+ * 	- increase module usage count as soon as we have rules inside
+ * 	  a table
  */
 #include <linux/config.h>
 #include <linux/skbuff.h>
@@ -84,6 +89,8 @@
 	unsigned int size;
 	/* Number of entries: FIXME. --RR */
 	unsigned int number;
+	/* Initial number of entries. Needed for module usage count */
+	unsigned int initial_entries;
 
 	/* Entry points and underflows */
 	unsigned int hook_entry[NF_IP_NUMHOOKS];
@@ -902,6 +909,7 @@
 	}
 	oldinfo = table->private;
 	table->private = newinfo;
+	newinfo->initial_entries = oldinfo->initial_entries;
 	write_unlock_bh(&table->lock);
 
 	return oldinfo;
@@ -1105,6 +1113,16 @@
 	if (!oldinfo)
 		goto free_newinfo_counters_untrans_unlock;
 
+	/* Update module usage count based on number of rules */
+	duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
+		oldinfo->number, oldinfo->initial_entries, newinfo->number);
+	if (t->me && (oldinfo->number <= oldinfo->initial_entries) &&
+ 	    (newinfo->number > oldinfo->initial_entries))
+		__MOD_INC_USE_COUNT(t->me);
+	else if (t->me && (oldinfo->number > oldinfo->initial_entries) &&
+	 	 (newinfo->number <= oldinfo->initial_entries))
+		__MOD_DEC_USE_COUNT(t->me);
+
 	/* Get the old counters. */
 	get_counters(oldinfo, counters);
 	/* Decrease module usage counts and free resource */
@@ -1363,7 +1381,7 @@
 	int ret;
 	struct ipt_table_info *newinfo;
 	static struct ipt_table_info bootstrap
-		= { 0, 0, { 0 }, { 0 }, { } };
+		= { 0, 0, 0, { 0 }, { 0 }, { } };
 
 	MOD_INC_USE_COUNT;
 	newinfo = vmalloc(sizeof(struct ipt_table_info)
@@ -1406,6 +1424,9 @@
 
 	duprintf("table->private->number = %u\n",
 		 table->private->number);
+	
+	/* save number of initial entries */
+	table->private->initial_entries = table->private->number;
 
 	table->lock = RW_LOCK_UNLOCKED;
 	list_prepend(&ipt_tables, table);
@@ -1746,7 +1767,7 @@
 	}
 #endif
 
-	printk("ip_tables: (c)2000 Netfilter core team\n");
+	printk("ip_tables: (C) 2000-2002 Netfilter core team\n");
 	return 0;
 }
 
diff -urN linux-2.4.18-pre6/net/ipv4/netfilter/ipchains_core.c linux/net/ipv4/netfilter/ipchains_core.c
--- linux-2.4.18-pre6/net/ipv4/netfilter/ipchains_core.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/ipchains_core.c	Wed Jan 23 15:04:33 2002
@@ -838,6 +838,7 @@
 			i->branch->refcount--;
 		kfree(i);
 		i = tmp;
+		MOD_DEC_USE_COUNT;
 	}
 	return 0;
 }
@@ -875,13 +876,16 @@
 		 * interrupts is not necessary. */
 		chainptr->chain = rule;
 		if (rule->branch) rule->branch->refcount++;
-		return 0;
+		goto append_successful;
 	}
 
 	/* Find the rule before the end of the chain */
 	for (i = chainptr->chain; i->next; i = i->next);
 	i->next = rule;
 	if (rule->branch) rule->branch->refcount++;
+
+append_successful:
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -900,7 +904,7 @@
 		frwl->next = chainptr->chain;
 		if (frwl->branch) frwl->branch->refcount++;
 		chainptr->chain = frwl;
-		return 0;
+		goto insert_successful;
 	}
 	position--;
 	while (--position && f != NULL) f = f->next;
@@ -910,6 +914,9 @@
 	frwl->next = f->next;
 
 	f->next = frwl;
+
+insert_successful:
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -943,6 +950,8 @@
 		i->next = i->next->next;
 		kfree(tmp);
 	}
+
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1049,6 +1058,7 @@
 		else
 			chainptr->chain = ftmp->next;
 		kfree(ftmp);
+		MOD_DEC_USE_COUNT;
 		break;
 	}
 
@@ -1089,6 +1099,8 @@
 
 	tmp->next = tmp2->next;
 	kfree(tmp2);
+
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1141,6 +1153,7 @@
 					      * user defined chain *
 					      * and therefore can be
 					      * deleted */
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
diff -urN linux-2.4.18-pre6/net/ipv4/netfilter/ipfwadm_core.c linux/net/ipv4/netfilter/ipfwadm_core.c
--- linux-2.4.18-pre6/net/ipv4/netfilter/ipfwadm_core.c	Thu Sep 20 14:12:56 2001
+++ linux/net/ipv4/netfilter/ipfwadm_core.c	Wed Jan 23 15:04:33 2002
@@ -20,7 +20,7 @@
  *	license in recognition of the original copyright.
  *				-- Alan Cox.
  *
- *	$Id: ipfwadm_core.c,v 1.9 2001/09/18 22:29:10 davem Exp $
+ *	$Id: ipfwadm_core.c,v 1.9.2.1 2002/01/23 13:18:19 davem Exp $
  *
  *	Ported from BSD to Linux,
  *		Alan Cox 22/Nov/1994.
@@ -104,6 +104,7 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/module.h>
 
 #include <linux/socket.h>
 #include <linux/sockios.h>
@@ -687,6 +688,7 @@
 		ftmp = *chainptr;
 		*chainptr = ftmp->fw_next;
 		kfree(ftmp);
+		MOD_DEC_USE_COUNT();
 	}
 	restore_flags(flags);
 }
@@ -730,6 +732,7 @@
 	ftmp->fw_next = *chainptr;
        	*chainptr=ftmp;
 	restore_flags(flags);
+	MOD_INC_USE_COUNT();
 	return(0);
 }
 
@@ -780,6 +783,7 @@
 	else
         	*chainptr=ftmp;
 	restore_flags(flags);
+	MOD_INC_USE_COUNT();
 	return(0);
 }
 
@@ -853,9 +857,10 @@
 		 }
 	}
 	restore_flags(flags);
-	if (was_found)
+	if (was_found) {
+		MOD_DEC_USE_COUNT();
 		return 0;
-	else
+	} else
 		return(EINVAL);
 }
 
diff -urN linux-2.4.18-pre6/net/ipv4/netfilter/ipt_LOG.c linux/net/ipv4/netfilter/ipt_LOG.c
--- linux-2.4.18-pre6/net/ipv4/netfilter/ipt_LOG.c	Mon Nov  5 09:53:07 2001
+++ linux/net/ipv4/netfilter/ipt_LOG.c	Wed Jan 23 15:04:33 2002
@@ -217,7 +217,7 @@
 				printk("[");
 				dump_packet(info,
 					    (struct iphdr *)(icmph + 1),
-					    datalen-sizeof(struct iphdr),
+					    datalen-sizeof(struct icmphdr),
 					    0);
 				printk("] ");
 			}
diff -urN linux-2.4.18-pre6/net/ipv4/netfilter/ipt_REDIRECT.c linux/net/ipv4/netfilter/ipt_REDIRECT.c
--- linux-2.4.18-pre6/net/ipv4/netfilter/ipt_REDIRECT.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/ipt_REDIRECT.c	Wed Jan 23 15:04:33 2002
@@ -74,10 +74,17 @@
 	/* Local packets: make them go to loopback */
 	if (hooknum == NF_IP_LOCAL_OUT)
 		newdst = htonl(0x7F000001);
-	else
+	else {
+		struct in_device *indev;
+
+		/* Device might not have an associated in_device. */
+		indev = (struct in_device *)(*pskb)->dev->ip_ptr;
+		if (indev == NULL)
+			return NF_DROP;
+
 		/* Grab first address on interface. */
-		newdst = (((struct in_device *)(*pskb)->dev->ip_ptr)
-			  ->ifa_list->ifa_local);
+		newdst = indev->ifa_list->ifa_local;
+	}
 
 	/* Transfer from original range. */
 	newrange = ((struct ip_nat_multi_range)
diff -urN linux-2.4.18-pre6/net/ipv4/netfilter/iptable_filter.c linux/net/ipv4/netfilter/iptable_filter.c
--- linux-2.4.18-pre6/net/ipv4/netfilter/iptable_filter.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/iptable_filter.c	Wed Jan 23 15:04:33 2002
@@ -83,7 +83,7 @@
 
 static struct ipt_table packet_filter
 = { { NULL, NULL }, "filter", &initial_table.repl,
-    FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
diff -urN linux-2.4.18-pre6/net/ipv4/netfilter/iptable_mangle.c linux/net/ipv4/netfilter/iptable_mangle.c
--- linux-2.4.18-pre6/net/ipv4/netfilter/iptable_mangle.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/iptable_mangle.c	Wed Jan 23 15:04:33 2002
@@ -2,6 +2,8 @@
  * This is the 1999 rewrite of IP Firewalling, aiming for kernel 2.3.x.
  *
  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ *
+ * Extended to all five netfilter hooks by Brad Chapman & Harald Welte
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -12,7 +14,11 @@
 #include <net/route.h>
 #include <linux/ip.h>
 
-#define MANGLE_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
+#define MANGLE_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | \
+			    (1 << NF_IP_LOCAL_IN) | \
+			    (1 << NF_IP_FORWARD) | \
+			    (1 << NF_IP_LOCAL_OUT) | \
+			    (1 << NF_IP_POST_ROUTING))
 
 /* Standard entry. */
 struct ipt_standard
@@ -33,18 +39,25 @@
 	struct ipt_error_target target;
 };
 
+/* Ouch - five different hooks? Maybe this should be a config option..... -- BC */
 static struct
 {
 	struct ipt_replace repl;
-	struct ipt_standard entries[2];
+	struct ipt_standard entries[5];
 	struct ipt_error term;
 } initial_table __initdata
-= { { "mangle", MANGLE_VALID_HOOKS, 3,
-      sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
-      { [NF_IP_PRE_ROUTING] 0,
-	[NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
-      { [NF_IP_PRE_ROUTING] 0,
-	[NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
+= { { "mangle", MANGLE_VALID_HOOKS, 6,
+      sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error),
+      { [NF_IP_PRE_ROUTING] 	0,
+	[NF_IP_LOCAL_IN] 	sizeof(struct ipt_standard),
+	[NF_IP_FORWARD] 	sizeof(struct ipt_standard) * 2,
+	[NF_IP_LOCAL_OUT] 	sizeof(struct ipt_standard) * 3,
+	[NF_IP_POST_ROUTING] 	sizeof(struct ipt_standard) * 4 },
+      { [NF_IP_PRE_ROUTING] 	0,
+	[NF_IP_LOCAL_IN] 	sizeof(struct ipt_standard),
+	[NF_IP_FORWARD] 	sizeof(struct ipt_standard) * 2,
+	[NF_IP_LOCAL_OUT] 	sizeof(struct ipt_standard) * 3,
+	[NF_IP_POST_ROUTING]	sizeof(struct ipt_standard) * 4 },
       0, NULL, { } },
     {
 	    /* PRE_ROUTING */
@@ -55,6 +68,22 @@
 		0, { 0, 0 }, { } },
 	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
 		-NF_ACCEPT - 1 } },
+	    /* LOCAL_IN */
+ 	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ipt_entry),
+		sizeof(struct ipt_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+	    /* FORWARD */
+ 	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ipt_entry),
+		sizeof(struct ipt_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
 	    /* LOCAL_OUT */
 	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
 		0,
@@ -62,7 +91,15 @@
 		sizeof(struct ipt_standard),
 		0, { 0, 0 }, { } },
 	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-		-NF_ACCEPT - 1 } }
+		-NF_ACCEPT - 1 } },
+	    /* POST_ROUTING */
+	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ipt_entry),
+		sizeof(struct ipt_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
     },
     /* ERROR */
     { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
@@ -79,11 +116,11 @@
 
 static struct ipt_table packet_mangler
 = { { NULL, NULL }, "mangle", &initial_table.repl,
-    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
-ipt_hook(unsigned int hook,
+ipt_route_hook(unsigned int hook,
 	 struct sk_buff **pskb,
 	 const struct net_device *in,
 	 const struct net_device *out,
@@ -121,7 +158,7 @@
 }
 
 static unsigned int
-ipt_local_out_hook(unsigned int hook,
+ipt_local_hook(unsigned int hook,
 		   struct sk_buff **pskb,
 		   const struct net_device *in,
 		   const struct net_device *out,
@@ -159,9 +196,16 @@
 }
 
 static struct nf_hook_ops ipt_ops[]
-= { { { NULL, NULL }, ipt_hook, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_MANGLE },
-    { { NULL, NULL }, ipt_local_out_hook, PF_INET, NF_IP_LOCAL_OUT,
-		NF_IP_PRI_MANGLE }
+= { { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_PRE_ROUTING, 
+	NF_IP_PRI_MANGLE },
+    { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_IN,
+	NF_IP_PRI_MANGLE },
+    { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_FORWARD,
+	NF_IP_PRI_MANGLE },
+    { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_OUT,
+	NF_IP_PRI_MANGLE },
+    { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_POST_ROUTING,
+	NF_IP_PRI_MANGLE }
 };
 
 static int __init init(void)
@@ -182,8 +226,26 @@
 	if (ret < 0)
 		goto cleanup_hook0;
 
+	ret = nf_register_hook(&ipt_ops[2]);
+	if (ret < 0)
+		goto cleanup_hook1;
+
+	ret = nf_register_hook(&ipt_ops[3]);
+	if (ret < 0)
+		goto cleanup_hook2;
+
+	ret = nf_register_hook(&ipt_ops[4]);
+	if (ret < 0)
+		goto cleanup_hook3;
+
 	return ret;
 
+ cleanup_hook3:
+        nf_unregister_hook(&ipt_ops[3]);
+ cleanup_hook2:
+        nf_unregister_hook(&ipt_ops[2]);
+ cleanup_hook1:
+	nf_unregister_hook(&ipt_ops[1]);
  cleanup_hook0:
 	nf_unregister_hook(&ipt_ops[0]);
  cleanup_table:
diff -urN linux-2.4.18-pre6/net/ipv4/route.c linux/net/ipv4/route.c
--- linux-2.4.18-pre6/net/ipv4/route.c	Fri Dec 21 09:42:05 2001
+++ linux/net/ipv4/route.c	Wed Jan 23 15:04:33 2002
@@ -5,7 +5,7 @@
  *
  *		ROUTE - implementation of the IP router.
  *
- * Version:	$Id: route.c,v 1.102 2001/10/31 21:55:54 davem Exp $
+ * Version:	$Id: route.c,v 1.102.2.1 2002/01/12 07:43:57 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -214,7 +214,7 @@
 {
 	int len = 0;
 	off_t pos = 128;
-	char temp[129];
+	char temp[256];
 	struct rtable *r;
 	int i;
 
diff -urN linux-2.4.18-pre6/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- linux-2.4.18-pre6/net/ipv4/tcp_ipv4.c	Fri Dec 21 09:42:05 2001
+++ linux/net/ipv4/tcp_ipv4.c	Wed Jan 23 15:04:33 2002
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.237 2001/12/05 08:54:10 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.237.2.1 2002/01/15 08:49:49 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -2064,7 +2064,7 @@
 	/* First, walk listening socket table. */
 	tcp_listen_lock();
 	for(i = 0; i < TCP_LHTABLE_SIZE; i++) {
-		struct sock *sk = tcp_listening_hash[i];
+		struct sock *sk;
 		struct tcp_listen_opt *lopt;
 		int k;
 
diff -urN linux-2.4.18-pre6/net/ipv4/udp.c linux/net/ipv4/udp.c
--- linux-2.4.18-pre6/net/ipv4/udp.c	Wed Oct 17 14:16:39 2001
+++ linux/net/ipv4/udp.c	Wed Jan 23 15:04:33 2002
@@ -5,7 +5,7 @@
  *
  *		The User Datagram Protocol (UDP).
  *
- * Version:	$Id: udp.c,v 1.100 2001/10/15 12:34:50 davem Exp $
+ * Version:	$Id: udp.c,v 1.100.2.1 2002/01/12 07:39:23 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -886,6 +886,9 @@
 	/*
 	 *	Validate the packet and the UDP length.
 	 */
+	if (!pskb_may_pull(skb, sizeof(struct udphdr)))
+		goto no_header;
+
 	ulen = ntohs(skb->h.uh->len);
 
 	if (ulen > len || ulen < sizeof(*uh))
@@ -926,6 +929,7 @@
 
 short_packet:
 	NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len));
+no_header:
 	UDP_INC_STATS_BH(UdpInErrors);
 	kfree_skb(skb);
 	return(0);
diff -urN linux-2.4.18-pre6/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c
--- linux-2.4.18-pre6/net/ipv6/ndisc.c	Fri Dec 21 09:42:05 2001
+++ linux/net/ipv6/ndisc.c	Wed Jan 23 15:04:33 2002
@@ -957,6 +957,7 @@
 	struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
 	struct neighbour *neigh;
 	struct inet6_ifaddr *ifp;
+	unsigned int payload_len;
 
 	__skb_push(skb, skb->data-skb->h.raw);
 
@@ -979,10 +980,11 @@
 	 *	(Some checking in ndisc_find_option)
 	 */
 
+	payload_len = ntohs(skb->nh.ipv6h->payload_len);
 	switch (msg->icmph.icmp6_type) {
 	case NDISC_NEIGHBOUR_SOLICITATION:
 		/* XXX: import nd_neighbor_solicit from glibc netinet/icmp6.h */
-		if (skb->nh.ipv6h->payload_len < 8+16) {
+		if (payload_len < 8+16) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP NS: packet too short\n");
 			return 0;
@@ -1112,7 +1114,7 @@
 
 	case NDISC_NEIGHBOUR_ADVERTISEMENT:
 		/* XXX: import nd_neighbor_advert from glibc netinet/icmp6.h */
-		if (skb->nh.ipv6h->payload_len < 16+8 ) {
+		if (payload_len < 16+8 ) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP NA: packet too short\n");
 			return 0;
@@ -1174,7 +1176,7 @@
 
 	case NDISC_ROUTER_ADVERTISEMENT:
 		/* XXX: import nd_router_advert from glibc netinet/icmp6.h */
-		if (skb->nh.ipv6h->payload_len < 8+4+4) {
+		if (payload_len < 8+4+4) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP RA: packet too short\n");
 			return 0;
@@ -1184,7 +1186,7 @@
 
 	case NDISC_REDIRECT:
 		/* XXX: import nd_redirect from glibc netinet/icmp6.h */
-		if (skb->nh.ipv6h->payload_len < 8+16+16) {
+		if (payload_len < 8+16+16) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP redirect: packet too short\n");
 			return 0;
@@ -1196,7 +1198,7 @@
 		/* No RS support in the kernel, but we do some required checks */
 
 		/* XXX: import nd_router_solicit from glibc netinet/icmp6.h */
-		if (skb->nh.ipv6h->payload_len < 8) {
+		if (payload_len < 8) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP RS: packet too short\n");
 			return 0;
diff -urN linux-2.4.18-pre6/net/ipv6/netfilter/Config.in linux/net/ipv6/netfilter/Config.in
--- linux-2.4.18-pre6/net/ipv6/netfilter/Config.in	Fri Dec 21 09:42:05 2001
+++ linux/net/ipv6/netfilter/Config.in	Wed Jan 23 15:04:33 2002
@@ -9,9 +9,10 @@
 #  dep_tristate '  FTP protocol support' CONFIG_IP6_NF_FTP $CONFIG_IP6_NF_CONNTRACK
 #fi
 
-#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-#  tristate 'Userspace queueing via NETLINK (EXPERIMENTAL)' CONFIG_IP6_NF_QUEUE
-#fi
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Userspace queueing via NETLINK (EXPERIMENTAL)' CONFIG_IP6_NF_QUEUE
+fi
+
 tristate 'IP6 tables support (required for filtering/masq/NAT)' CONFIG_IP6_NF_IPTABLES
 if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ]; then
 # The simple matches.
diff -urN linux-2.4.18-pre6/net/ipv6/netfilter/Makefile linux/net/ipv6/netfilter/Makefile
--- linux-2.4.18-pre6/net/ipv6/netfilter/Makefile	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv6/netfilter/Makefile	Wed Jan 23 15:04:33 2002
@@ -21,6 +21,7 @@
 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
 obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
+obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.18-pre6/net/ipv6/netfilter/ip6_tables.c linux/net/ipv6/netfilter/ip6_tables.c
--- linux-2.4.18-pre6/net/ipv6/netfilter/ip6_tables.c	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv6/netfilter/ip6_tables.c	Wed Jan 23 15:04:33 2002
@@ -2,6 +2,11 @@
  * Packet matching code.
  *
  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2000-2002 Netfilter core team <coreteam@netfilter.org>
+ *
+ * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
+ * 	- increase module usage count as soon as we have rules inside
+ * 	  a table
  */
 #include <linux/config.h>
 #include <linux/skbuff.h>
@@ -86,6 +91,8 @@
 	unsigned int size;
 	/* Number of entries: FIXME. --RR */
 	unsigned int number;
+	/* Initial number of entries. Needed for module usage count */
+	unsigned int initial_entries;
 
 	/* Entry points and underflows */
 	unsigned int hook_entry[NF_IP6_NUMHOOKS];
@@ -949,6 +956,7 @@
 	}
 	oldinfo = table->private;
 	table->private = newinfo;
+	newinfo->initial_entries = oldinfo->initial_entries;
 	write_unlock_bh(&table->lock);
 
 	return oldinfo;
@@ -1148,6 +1156,16 @@
 	if (!oldinfo)
 		goto free_newinfo_counters_untrans_unlock;
 
+	/* Update module usage count based on number of rules */
+	duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
+		oldinfo->number, oldinfo->initial_entries, newinfo->number);
+	if (t->me && (oldinfo->number <= oldinfo->initial_entries) &&
+ 	    (newinfo->number > oldinfo->initial_entries))
+		__MOD_INC_USE_COUNT(t->me);
+	else if (t->me && (oldinfo->number > oldinfo->initial_entries) &&
+	 	 (newinfo->number <= oldinfo->initial_entries))
+		__MOD_DEC_USE_COUNT(t->me);
+
 	/* Get the old counters. */
 	get_counters(oldinfo, counters);
 	/* Decrease module usage counts and free resource */
@@ -1406,7 +1424,7 @@
 	int ret;
 	struct ip6t_table_info *newinfo;
 	static struct ip6t_table_info bootstrap
-		= { 0, 0, { 0 }, { 0 }, { }, { } };
+		= { 0, 0, 0, { 0 }, { 0 }, { }, { } };
 
 	MOD_INC_USE_COUNT;
 	newinfo = vmalloc(sizeof(struct ip6t_table_info)
@@ -1783,7 +1801,7 @@
 	}
 #endif
 
-	printk("ip6_tables: (c)2000 Netfilter core team\n");
+	printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
 	return 0;
 }
 
diff -urN linux-2.4.18-pre6/net/ipv6/netfilter/ip6t_MARK.c linux/net/ipv6/netfilter/ip6t_MARK.c
--- linux-2.4.18-pre6/net/ipv6/netfilter/ip6t_MARK.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv6/netfilter/ip6t_MARK.c	Wed Jan 23 15:04:33 2002
@@ -51,7 +51,7 @@
 
 static int __init init(void)
 {
-	printk(KERN_DEBUG "registreing ipv6 mark target\n");
+	printk(KERN_DEBUG "registering ipv6 mark target\n");
 	if (ip6t_register_target(&ip6t_mark_reg))
 		return -EINVAL;
 
diff -urN linux-2.4.18-pre6/net/ipv6/netfilter/ip6table_filter.c linux/net/ipv6/netfilter/ip6table_filter.c
--- linux-2.4.18-pre6/net/ipv6/netfilter/ip6table_filter.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv6/netfilter/ip6table_filter.c	Wed Jan 23 15:04:33 2002
@@ -83,7 +83,7 @@
 
 static struct ip6t_table packet_filter
 = { { NULL, NULL }, "filter", &initial_table.repl,
-    FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
diff -urN linux-2.4.18-pre6/net/ipv6/netfilter/ip6table_mangle.c linux/net/ipv6/netfilter/ip6table_mangle.c
--- linux-2.4.18-pre6/net/ipv6/netfilter/ip6table_mangle.c	Sun Sep 30 12:26:09 2001
+++ linux/net/ipv6/netfilter/ip6table_mangle.c	Wed Jan 23 15:04:33 2002
@@ -1,14 +1,18 @@
 /*
  * IPv6 packet mangling table, a port of the IPv4 mangle table to IPv6
  *
- * Copyright (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * Copyright (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
  */
 #include <linux/module.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 
-#define MANGLE_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT))
+#define MANGLE_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | \
+			    (1 << NF_IP6_LOCAL_IN) | \
+			    (1 << NF_IP6_FORWARD) | \
+			    (1 << NF_IP6_LOCAL_OUT) | \
+			    (1 << NF_IP6_POST_ROUTING))
 
-#if 1
+#if 0
 #define DEBUGP(x, args...)	printk(KERN_DEBUG x, ## args)
 #else
 #define DEBUGP(x, args...)
@@ -36,19 +40,41 @@
 static struct
 {
 	struct ip6t_replace repl;
-	struct ip6t_standard entries[2];
+	struct ip6t_standard entries[5];
 	struct ip6t_error term;
 } initial_table __initdata
-= { { "mangle", MANGLE_VALID_HOOKS, 3,
-      sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error),
-      { [NF_IP6_PRE_ROUTING] 0,
-	[NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
-      { [NF_IP6_PRE_ROUTING] 0,
-	[NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
+= { { "mangle", MANGLE_VALID_HOOKS, 6,
+      sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
+      { [NF_IP6_PRE_ROUTING] 	0,
+	[NF_IP6_LOCAL_IN]	sizeof(struct ip6t_standard),
+	[NF_IP6_FORWARD]	sizeof(struct ip6t_standard) * 2,
+	[NF_IP6_LOCAL_OUT] 	sizeof(struct ip6t_standard) * 3,
+	[NF_IP6_POST_ROUTING]	sizeof(struct ip6t_standard) * 4},
+      { [NF_IP6_PRE_ROUTING] 	0,
+	[NF_IP6_LOCAL_IN]	sizeof(struct ip6t_standard),
+	[NF_IP6_FORWARD]	sizeof(struct ip6t_standard) * 2,
+	[NF_IP6_LOCAL_OUT] 	sizeof(struct ip6t_standard) * 3,
+	[NF_IP6_POST_ROUTING]	sizeof(struct ip6t_standard) * 4},
       0, NULL, { } },
     {
 	    /* PRE_ROUTING */
-	    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ip6t_entry),
+		sizeof(struct ip6t_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+	    /* LOCAL_IN */
+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ip6t_entry),
+		sizeof(struct ip6t_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+	    /* FORWARD */
+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
 		0,
 		sizeof(struct ip6t_entry),
 		sizeof(struct ip6t_standard),
@@ -56,6 +82,14 @@
 	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
 		-NF_ACCEPT - 1 } },
 	    /* LOCAL_OUT */
+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ip6t_entry),
+		sizeof(struct ip6t_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+	    /* POST_ROUTING */
 	    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
 		0,
 		sizeof(struct ip6t_entry),
@@ -79,11 +113,11 @@
 
 static struct ip6t_table packet_mangler
 = { { NULL, NULL }, "mangle", &initial_table.repl,
-    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
-ip6t_hook(unsigned int hook,
+ip6t_route_hook(unsigned int hook,
 	 struct sk_buff **pskb,
 	 const struct net_device *in,
 	 const struct net_device *out,
@@ -93,7 +127,7 @@
 }
 
 static unsigned int
-ip6t_local_out_hook(unsigned int hook,
+ip6t_local_hook(unsigned int hook,
 		   struct sk_buff **pskb,
 		   const struct net_device *in,
 		   const struct net_device *out,
@@ -142,9 +176,11 @@
 }
 
 static struct nf_hook_ops ip6t_ops[]
-= { { { NULL, NULL }, ip6t_hook, PF_INET6, NF_IP6_PRE_ROUTING, NF_IP6_PRI_MANGLE },
-    { { NULL, NULL }, ip6t_local_out_hook, PF_INET6, NF_IP6_LOCAL_OUT,
-		NF_IP6_PRI_MANGLE }
+= { { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_PRE_ROUTING,  NF_IP6_PRI_MANGLE },
+    { { NULL, NULL }, ip6t_local_hook, PF_INET6, NF_IP6_LOCAL_IN,     NF_IP6_PRI_MANGLE },
+    { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_FORWARD,      NF_IP6_PRI_MANGLE },
+    { { NULL, NULL }, ip6t_local_hook, PF_INET6, NF_IP6_LOCAL_OUT,    NF_IP6_PRI_MANGLE },
+    { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_POST_ROUTING, NF_IP6_PRI_MANGLE }
 };
 
 static int __init init(void)
@@ -165,8 +201,26 @@
 	if (ret < 0)
 		goto cleanup_hook0;
 
+	ret = nf_register_hook(&ip6t_ops[2]);
+	if (ret < 0)
+		goto cleanup_hook1;
+
+	ret = nf_register_hook(&ip6t_ops[3]);
+	if (ret < 0)
+		goto cleanup_hook2;
+
+	ret = nf_register_hook(&ip6t_ops[4]);
+	if (ret < 0)
+		goto cleanup_hook3;
+
 	return ret;
 
+ cleanup_hook3:
+        nf_unregister_hook(&ip6t_ops[3]);
+ cleanup_hook2:
+	nf_unregister_hook(&ip6t_ops[2]);
+ cleanup_hook1:
+	nf_unregister_hook(&ip6t_ops[1]);
  cleanup_hook0:
 	nf_unregister_hook(&ip6t_ops[0]);
  cleanup_table:
diff -urN linux-2.4.18-pre6/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c
--- linux-2.4.18-pre6/net/netlink/af_netlink.c	Fri Jun 29 19:38:26 2001
+++ linux/net/netlink/af_netlink.c	Wed Jan 23 15:04:33 2002
@@ -36,7 +36,7 @@
 #include <asm/uaccess.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
 #include <linux/proc_fs.h>
 #include <linux/smp_lock.h>
 #include <net/sock.h>
@@ -47,8 +47,6 @@
 #if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE)
 #define NL_EMULATE_DEV
 #endif
-
-#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); }
 
 struct netlink_opt
 {
diff -urN linux-2.4.18-pre6/net/netsyms.c linux/net/netsyms.c
--- linux-2.4.18-pre6/net/netsyms.c	Wed Jan 23 15:04:30 2002
+++ linux/net/netsyms.c	Wed Jan 23 15:04:33 2002
@@ -292,6 +292,8 @@
 EXPORT_SYMBOL(ndisc_mc_map);
 EXPORT_SYMBOL(register_inet6addr_notifier);
 EXPORT_SYMBOL(unregister_inet6addr_notifier);
+#include <net/ip6_route.h>
+EXPORT_SYMBOL(ip6_route_output);
 #endif
 #if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_KHTTPD) || defined (CONFIG_KHTTPD_MODULE)
 /* inet functions common to v4 and v6 */
diff -urN linux-2.4.18-pre6/net/unix/af_unix.c linux/net/unix/af_unix.c
--- linux-2.4.18-pre6/net/unix/af_unix.c	Wed Jan 23 15:04:30 2002
+++ linux/net/unix/af_unix.c	Wed Jan 23 15:04:33 2002
@@ -8,7 +8,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * Version:	$Id: af_unix.c,v 1.126 2001/11/13 05:06:28 davem Exp $
+ * Version:	$Id: af_unix.c,v 1.126.2.4 2002/01/14 07:07:41 davem Exp $
  *
  * Fixes:
  *		Linus Torvalds	:	Assorted bug cures.
@@ -101,13 +101,14 @@
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <linux/tcp.h>
 #include <net/af_unix.h>
 #include <linux/proc_fs.h>
 #include <net/scm.h>
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
+#include <linux/rtnetlink.h>
 
 #include <asm/checksum.h>
 
@@ -483,7 +484,7 @@
 	sk->protinfo.af_unix.dentry=NULL;
 	sk->protinfo.af_unix.mnt=NULL;
 	sk->protinfo.af_unix.lock = RW_LOCK_UNLOCKED;
-	atomic_set(&sk->protinfo.af_unix.inflight, 0);
+	atomic_set(&sk->protinfo.af_unix.inflight, sock ? 0 : -1);
 	init_MUTEX(&sk->protinfo.af_unix.readsem);/* single task reading lock */
 	init_waitqueue_head(&sk->protinfo.af_unix.peer_wait);
 	sk->protinfo.af_unix.list=NULL;
@@ -990,7 +991,12 @@
 	unix_state_wunlock(sk);
 
 	/* take ten and and send info to listening sock */
-	skb_queue_tail(&other->receive_queue,skb);
+	spin_lock(&other->receive_queue.lock);
+	__skb_queue_tail(&other->receive_queue,skb);
+	/* Undo artificially decreased inflight after embrion
+	 * is installed to listening socket. */
+	atomic_inc(&newsk->protinfo.af_unix.inflight);
+	spin_unlock(&other->receive_queue.lock);
 	unix_state_runlock(other);
 	other->data_ready(other, 0);
 	sock_put(other);
diff -urN linux-2.4.18-pre6/net/unix/garbage.c linux/net/unix/garbage.c
--- linux-2.4.18-pre6/net/unix/garbage.c	Fri Jun 29 19:38:26 2001
+++ linux/net/unix/garbage.c	Wed Jan 23 15:04:33 2002
@@ -76,9 +76,9 @@
 #include <linux/netdevice.h>
 #include <linux/file.h>
 #include <linux/proc_fs.h>
+#include <linux/tcp.h>
 
 #include <net/sock.h>
-#include <net/tcp.h>
 #include <net/af_unix.h>
 #include <net/scm.h>
 
@@ -205,12 +205,21 @@
 
 	forall_unix_sockets(i, s)
 	{
+		int open_count = 0;
+
 		/*
 		 *	If all instances of the descriptor are not
 		 *	in flight we are in use.
+		 *
+		 *	Special case: when socket s is embrion, it may be
+		 *	hashed but still not in queue of listening socket.
+		 *	In this case (see unix_create1()) we set artificial
+		 *	negative inflight counter to close race window.
+		 *	It is trick of course and dirty one.
 		 */
-		if(s->socket && s->socket->file &&
-		   file_count(s->socket->file) > atomic_read(&s->protinfo.af_unix.inflight))
+		if(s->socket && s->socket->file)
+			open_count = file_count(s->socket->file);
+		if (open_count > atomic_read(&s->protinfo.af_unix.inflight))
 			maybe_unmark_and_push(s);
 	}
 
