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

diff -urN linux-2.5.74-bk4/Documentation/filesystems/Locking linux-2.5.74-bk5/Documentation/filesystems/Locking
--- linux-2.5.74-bk4/Documentation/filesystems/Locking	2003-07-07 04:56:52.000000000 -0700
+++ linux-2.5.74-bk5/Documentation/filesystems/Locking	2003-07-07 04:57:13.000000000 -0700
@@ -68,8 +68,8 @@
 permission:	no
 getattr:	no
 setxattr:	yes
-getxattr:	yes
-listxattr:	yes
+getxattr:	no
+listxattr:	no
 removexattr:	yes
 	Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_sem on
 victim.
diff -urN linux-2.5.74-bk4/MAINTAINERS linux-2.5.74-bk5/MAINTAINERS
--- linux-2.5.74-bk4/MAINTAINERS	2003-07-02 13:49:30.000000000 -0700
+++ linux-2.5.74-bk5/MAINTAINERS	2003-07-07 04:57:13.000000000 -0700
@@ -1265,8 +1265,8 @@
 S:	Maintained
 
 NETWORK BLOCK DEVICE
-P:	Pavel Machek
-M:	pavel@atrey.karlin.mff.cuni.cz
+P:	Paul Clements
+M:	Paul.Clements@steeleye.com
 S:	Maintained
 
 NETWORK DEVICE DRIVERS
diff -urN linux-2.5.74-bk4/Makefile linux-2.5.74-bk5/Makefile
--- linux-2.5.74-bk4/Makefile	2003-07-07 04:56:52.000000000 -0700
+++ linux-2.5.74-bk5/Makefile	2003-07-07 04:57:14.000000000 -0700
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 74
-EXTRAVERSION = -bk4
+EXTRAVERSION = -bk5
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
diff -urN linux-2.5.74-bk4/arch/m68knommu/platform/5282/config.c linux-2.5.74-bk5/arch/m68knommu/platform/5282/config.c
--- linux-2.5.74-bk4/arch/m68knommu/platform/5282/config.c	2003-07-02 13:40:06.000000000 -0700
+++ linux-2.5.74-bk5/arch/m68knommu/platform/5282/config.c	2003-07-07 04:57:14.000000000 -0700
@@ -62,7 +62,7 @@
 {
 	mcf_disableall();
 
-#if defined(CONFIG_BOOTPARAM)
+#ifdef CONFIG_BOOTPARAM
 	strncpy(commandp, CONFIG_BOOTPARAM_STRING, size);
 	commandp[size-1] = 0;
 #else
diff -urN linux-2.5.74-bk4/arch/m68knommu/platform/5307/CLEOPATRA/crt0_ram.S linux-2.5.74-bk5/arch/m68knommu/platform/5307/CLEOPATRA/crt0_ram.S
--- linux-2.5.74-bk4/arch/m68knommu/platform/5307/CLEOPATRA/crt0_ram.S	2003-07-02 13:46:00.000000000 -0700
+++ linux-2.5.74-bk5/arch/m68knommu/platform/5307/CLEOPATRA/crt0_ram.S	2003-07-07 04:57:14.000000000 -0700
@@ -127,6 +127,7 @@
 	movc  %d0,%CACR
 
 
+#ifdef CONFIG_ROMFS_FS
 	/*
 	 *	Move ROM filesystem above bss :-)
 	 */
@@ -148,6 +149,12 @@
 	cmp.l	%a0, %a2			/* Check if at end */
 	bne	_copy_romfs
 
+#else /* CONFIG_ROMFS_FS */
+	lea.l	_ebss, %a1
+	move.l	%a1, _ramstart
+#endif /* CONFIG_ROMFS_FS */
+
+
 	/*
 	 *	Zero out the bss region.
 	 */
diff -urN linux-2.5.74-bk4/arch/m68knommu/platform/5307/MOTOROLA/crt0_ram.S linux-2.5.74-bk5/arch/m68knommu/platform/5307/MOTOROLA/crt0_ram.S
--- linux-2.5.74-bk4/arch/m68knommu/platform/5307/MOTOROLA/crt0_ram.S	2003-07-02 13:53:48.000000000 -0700
+++ linux-2.5.74-bk5/arch/m68knommu/platform/5307/MOTOROLA/crt0_ram.S	2003-07-07 04:57:14.000000000 -0700
@@ -110,6 +110,8 @@
 	movc  %d0,%CACR
 	nop
 
+
+#ifdef CONFIG_ROMFS_FS
 	/*
 	 *	Move ROM filesystem above bss :-)
 	 */
@@ -131,6 +133,12 @@
 	cmp.l	%a0, %a2			/* Check if at end */
 	bne	_copy_romfs
 
+#else /* CONFIG_ROMFS_FS */
+	lea.l	_ebss, %a1
+	move.l	%a1, _ramstart
+#endif /* CONFIG_ROMFS_FS */
+
+
 	/*
 	 *	Zero out the bss region.
 	 */
diff -urN linux-2.5.74-bk4/drivers/char/pcmcia/synclink_cs.c linux-2.5.74-bk5/drivers/char/pcmcia/synclink_cs.c
--- linux-2.5.74-bk4/drivers/char/pcmcia/synclink_cs.c	2003-07-02 13:45:16.000000000 -0700
+++ linux-2.5.74-bk5/drivers/char/pcmcia/synclink_cs.c	2003-07-07 04:57:14.000000000 -0700
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/pcmcia/synclink_cs.c
  *
- * $Id: synclink_cs.c,v 4.10 2003/05/13 16:06:03 paulkf Exp $
+ * $Id: synclink_cs.c,v 4.13 2003/06/18 15:29:32 paulkf Exp $
  *
  * Device driver for Microgate SyncLink PC Card
  * multiprotocol serial adapter.
@@ -467,7 +467,6 @@
  * assigned major number. May be forced as module parameter.
  */
 static int ttymajor=0;
-static int cuamajor=0;
 
 static int debug_level = 0;
 static int maxframe[MAX_DEVICE_COUNT] = {0,};
@@ -485,7 +484,6 @@
 
 MODULE_PARM(break_on_load,"i");
 MODULE_PARM(ttymajor,"i");
-MODULE_PARM(cuamajor,"i");
 MODULE_PARM(debug_level,"i");
 MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICE_COUNT) "i");
 MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICE_COUNT) "i");
@@ -493,7 +491,7 @@
 MODULE_LICENSE("GPL");
 
 static char *driver_name = "SyncLink PC Card driver";
-static char *driver_version = "$Revision: 4.10 $";
+static char *driver_version = "$Revision: 4.13 $";
 
 static struct tty_driver *serial_driver;
 
@@ -1290,7 +1288,7 @@
 			       (info->serial_signals & SerialSignal_DCD) ? "on" : "off");
 		if (info->serial_signals & SerialSignal_DCD)
 			wake_up_interruptible(&info->open_wait);
-		else if (!(info->flags & ASYNC_CALLOUT_NOHUP)) {
+		else {
 			if (debug_level >= DEBUG_LEVEL_ISR)
 				printk("doing serial hangup...");
 			if (info->tty)
@@ -2538,14 +2536,17 @@
 {
 	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
 
-	if (!info || mgslpc_paranoia_check(info, tty->name, "mgslpc_close"))
+	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_close"))
 		return;
 	
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):mgslpc_close(%s) entry, count=%d\n",
 			 __FILE__,__LINE__, info->device_name, info->count);
 			 
-	if (!info->count || tty_hung_up_p(filp))
+	if (!info->count)
+		return;
+
+	if (tty_hung_up_p(filp))
 		goto cleanup;
 			
 	if ((tty->count == 1) && (info->count != 1)) {
@@ -2822,16 +2823,11 @@
 	info = mgslpc_device_list;
 	while(info && info->line != line)
 		info = info->next_device;
-	if ( !info ){
-		printk("%s(%d):Can't find specified device on open (line=%d)\n",
-			__FILE__,__LINE__,line);
+	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_open"))
 		return -ENODEV;
-	}
 	
 	tty->driver_data = info;
 	info->tty = tty;
-	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_open"))
-		return -ENODEV;
 		
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):mgslpc_open(%s), old ref count = %d\n",
@@ -2879,6 +2875,8 @@
 	
 cleanup:			
 	if (retval) {
+		if (tty->count == 1)
+			info->tty = 0; /* tty layer will release tty struct */
 		if(info->count)
 			info->count--;
 	}
diff -urN linux-2.5.74-bk4/drivers/char/synclink.c linux-2.5.74-bk5/drivers/char/synclink.c
--- linux-2.5.74-bk4/drivers/char/synclink.c	2003-07-02 13:45:21.000000000 -0700
+++ linux-2.5.74-bk5/drivers/char/synclink.c	2003-07-07 04:57:14.000000000 -0700
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/synclink.c
  *
- * $Id: synclink.c,v 4.9 2003/05/06 21:18:51 paulkf Exp $
+ * $Id: synclink.c,v 4.12 2003/06/18 15:29:32 paulkf Exp $
  *
  * Device driver for Microgate SyncLink ISA and PCI
  * high speed multiprotocol serial adapters.
@@ -910,7 +910,7 @@
 MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
 
 static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "$Revision: 4.9 $";
+static char *driver_version = "$Revision: 4.12 $";
 
 static int synclink_init_one (struct pci_dev *dev,
 				     const struct pci_device_id *ent);
@@ -3170,14 +3170,17 @@
 {
 	struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
 
-	if (!info || mgsl_paranoia_check(info, tty->name, "mgsl_close"))
+	if (mgsl_paranoia_check(info, tty->name, "mgsl_close"))
 		return;
 	
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):mgsl_close(%s) entry, count=%d\n",
 			 __FILE__,__LINE__, info->device_name, info->count);
 			 
-	if (!info->count || tty_hung_up_p(filp))
+	if (!info->count)
+		return;
+
+	if (tty_hung_up_p(filp))
 		goto cleanup;
 			
 	if ((tty->count == 1) && (info->count != 1)) {
@@ -3493,16 +3496,11 @@
 	info = mgsl_device_list;
 	while(info && info->line != line)
 		info = info->next_device;
-	if ( !info ){
-		printk("%s(%d):Can't find specified device on open (line=%d)\n",
-			__FILE__,__LINE__,line);
+	if (mgsl_paranoia_check(info, tty->name, "mgsl_open"))
 		return -ENODEV;
-	}
 	
 	tty->driver_data = info;
 	info->tty = tty;
-	if (mgsl_paranoia_check(info, tty->name, "mgsl_open"))
-		return -ENODEV;
 		
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):mgsl_open(%s), old ref count = %d\n",
@@ -3562,6 +3560,8 @@
 	
 cleanup:			
 	if (retval) {
+		if (tty->count == 1)
+			info->tty = 0; /* tty layer will release tty struct */
 		if(info->count)
 			info->count--;
 	}
@@ -4461,7 +4461,6 @@
 int mgsl_init_tty(void);
 int mgsl_init_tty()
 {
-	struct mgsl_struct *info;
 	serial_driver = alloc_tty_driver(mgsl_device_count);
 	if (!serial_driver)
 		return -ENOMEM;
diff -urN linux-2.5.74-bk4/drivers/char/synclinkmp.c linux-2.5.74-bk5/drivers/char/synclinkmp.c
--- linux-2.5.74-bk4/drivers/char/synclinkmp.c	2003-07-02 13:42:49.000000000 -0700
+++ linux-2.5.74-bk5/drivers/char/synclinkmp.c	2003-07-07 04:57:14.000000000 -0700
@@ -1,5 +1,5 @@
 /*
- * $Id: synclinkmp.c,v 4.8 2003/04/21 17:46:55 paulkf Exp $
+ * $Id: synclinkmp.c,v 4.12 2003/06/18 15:29:33 paulkf Exp $
  *
  * Device driver for Microgate SyncLink Multiport
  * high speed multiprotocol serial adapter.
@@ -481,7 +481,6 @@
  * assigned major number. May be forced as module parameter.
  */
 static int ttymajor=0;
-static int cuamajor=0;
 
 /*
  * Array of user specified options for ISA adapters.
@@ -492,13 +491,12 @@
 
 MODULE_PARM(break_on_load,"i");
 MODULE_PARM(ttymajor,"i");
-MODULE_PARM(cuamajor,"i");
 MODULE_PARM(debug_level,"i");
 MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICES) "i");
 MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i");
 
 static char *driver_name = "SyncLink MultiPort driver";
-static char *driver_version = "$Revision: 4.8 $";
+static char *driver_version = "$Revision: 4.12 $";
 
 static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent);
 static void synclinkmp_remove_one(struct pci_dev *dev);
@@ -739,12 +737,8 @@
 	info = synclinkmp_device_list;
 	while(info && info->line != line)
 		info = info->next_device;
-	if ( !info ){
-		printk("%s(%d):%s Can't find specified device on open (line=%d)\n",
-			__FILE__,__LINE__,info->device_name,line);
+	if (sanity_check(info, tty->name, "open"))
 		return -ENODEV;
-	}
-
 	if ( info->init_error ) {
 		printk("%s(%d):%s device is not allocated, init error=%d\n",
 			__FILE__,__LINE__,info->device_name,info->init_error);
@@ -753,8 +747,6 @@
 
 	tty->driver_data = info;
 	info->tty = tty;
-	if (sanity_check(info, tty->name, "open"))
-		return -ENODEV;
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):%s open(), old ref count = %d\n",
@@ -802,6 +794,8 @@
 
 cleanup:
 	if (retval) {
+		if (tty->count == 1)
+			info->tty = 0; /* tty layer will release tty struct */
 		if(info->count)
 			info->count--;
 	}
@@ -816,14 +810,17 @@
 {
 	SLMP_INFO * info = (SLMP_INFO *)tty->driver_data;
 
-	if (!info || sanity_check(info, tty->name, "close"))
+	if (sanity_check(info, tty->name, "close"))
 		return;
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):%s close() entry, count=%d\n",
 			 __FILE__,__LINE__, info->device_name, info->count);
 
-	if (!info->count || tty_hung_up_p(filp))
+	if (!info->count)
+		return;
+
+	if (tty_hung_up_p(filp))
 		goto cleanup;
 
 	if ((tty->count == 1) && (info->count != 1)) {
@@ -3775,8 +3772,6 @@
 
 static int __init synclinkmp_init(void)
 {
-	SLMP_INFO *info;
-
 	if (break_on_load) {
 	 	synclinkmp_get_text_ptr();
   		BREAKPOINT();
diff -urN linux-2.5.74-bk4/drivers/ide/ppc/pmac.c linux-2.5.74-bk5/drivers/ide/ppc/pmac.c
--- linux-2.5.74-bk4/drivers/ide/ppc/pmac.c	2003-07-02 13:41:10.000000000 -0700
+++ linux-2.5.74-bk5/drivers/ide/ppc/pmac.c	2003-07-07 04:57:14.000000000 -0700
@@ -1514,6 +1514,8 @@
 	ide_hwifs[ix].ide_dma_timeout = &__ide_dma_timeout;
 	ide_hwifs[ix].ide_dma_retune = &__ide_dma_retune;
 	ide_hwifs[ix].ide_dma_lostirq = &pmac_ide_dma_lostirq;
+	ide_hwifs[ix].ide_dma_queued_on = &__ide_dma_queued_on;
+	ide_hwifs[ix].ide_dma_queued_off = &__ide_dma_queued_off;
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
 	if (!noautodma)
diff -urN linux-2.5.74-bk4/drivers/serial/8250_cs.c linux-2.5.74-bk5/drivers/serial/8250_cs.c
--- linux-2.5.74-bk4/drivers/serial/8250_cs.c	2003-07-02 13:47:33.000000000 -0700
+++ linux-2.5.74-bk5/drivers/serial/8250_cs.c	2003-07-07 04:57:15.000000000 -0700
@@ -133,7 +133,7 @@
 static void serial_remove(dev_link_t *link)
 {
 	struct serial_info *info = link->priv;
-	int i, ret;
+	int i;
 
 	link->state &= ~DEV_PRESENT;
 
diff -urN linux-2.5.74-bk4/fs/binfmt_flat.c linux-2.5.74-bk5/fs/binfmt_flat.c
--- linux-2.5.74-bk4/fs/binfmt_flat.c	2003-07-02 13:39:14.000000000 -0700
+++ linux-2.5.74-bk5/fs/binfmt_flat.c	2003-07-07 04:57:15.000000000 -0700
@@ -1,15 +1,17 @@
+/****************************************************************************/
 /*
  *  linux/fs/binfmt_flat.c
  *
- *	Copyright (C) 2000, 2001 Lineo, by David McCullough <davidm@uclinux.org>
+ *	Copyright (C) 2000-2003 David McCullough <davidm@snapgear.com>
  *	Copyright (C) 2002 Greg Ungerer <gerg@snapgear.com>
- *
+ *	Copyright (C) 2002 SnapGear, by Paul Dale <pauli@snapgear.com>
+ *	Copyright (C) 2000, 2001 Lineo, by David McCullough <davidm@lineo.com>
  *  based heavily on:
  *
  *  linux/fs/binfmt_aout.c:
  *      Copyright (C) 1991, 1992, 1996  Linus Torvalds
  *  linux/fs/binfmt_flat.c for 2.0 kernel
- *	Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>
+ *	    Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>
  *	JAN/99 -- coded full program relocation (gerg@snapgear.com)
  */
 
@@ -42,27 +44,69 @@
 #include <asm/unaligned.h>
 #include <asm/cacheflush.h>
 
-#undef DEBUG
+/****************************************************************************/
+
+#if 0
+#define DEBUG 1
+#endif
+
 #ifdef DEBUG
-#define	DBG_FLT(a...)	printk(##a)
+#define	DBG_FLT(a...)	printk(a)
 #else
 #define	DBG_FLT(a...)
 #endif
 
+#define RELOC_FAILED 0xff00ff01		/* Relocation incorrect somewhere */
+#define UNLOADED_LIB 0x7ff000ff		/* Placeholder for unused library */
+
+struct lib_info {
+	struct {
+		unsigned long start_code;		/* Start of text segment */
+		unsigned long start_data;		/* Start of data segment */
+		unsigned long start_brk;		/* End of data segment */
+		unsigned long text_len;			/* Length of text segment */
+		unsigned long entry;			/* Start address for this module */
+		unsigned long build_date;		/* When this one was compiled */
+		short loaded;				/* Has this library been loaded? */
+	} lib_list[MAX_SHARED_LIBS];
+};
+
+#ifdef CONFIG_BINFMT_SHARED_FLAT
+static int load_flat_shared_library(int id, struct lib_info *p);
+#endif
+
 static int load_flat_binary(struct linux_binprm *, struct pt_regs * regs);
-static int load_flat_library(struct file*);
+static int flat_core_dump(long signr, struct pt_regs * regs, struct file *file);
+
 extern void dump_thread(struct pt_regs *, struct user *);
 
 static struct linux_binfmt flat_format = {
-	NULL, THIS_MODULE, load_flat_binary, load_flat_library, NULL, PAGE_SIZE
+	.module		= THIS_MODULE,
+	.load_binary	= load_flat_binary,
+	.core_dump	= flat_core_dump,
+	.min_coredump	= PAGE_SIZE
 };
 
+/****************************************************************************/
+/*
+ * Routine writes a core dump image in the current directory.
+ * Currently only a stub-function.
+ */
+
+static int flat_core_dump(long signr, struct pt_regs * regs, struct file *file)
+{
+	printk("Process %s:%d received signr %d and should have core dumped\n",
+			current->comm, current->pid, (int) signr);
+	return(1);
+}
 
+/****************************************************************************/
 /*
  * create_flat_tables() parses the env- and arg-strings in new user
  * memory and creates the pointer tables from them, and puts their
  * addresses on the "stack", returning the new stack pointer value.
  */
+
 static unsigned long create_flat_tables(
 	unsigned long pp,
 	struct linux_binprm * bprm)
@@ -80,10 +124,13 @@
 	envp = sp;
 	sp -= argc+1;
 	argv = sp;
+
+	flat_stack_align(sp);
 	if (flat_argvp_envp_on_stack()) {
-		put_user((unsigned long) envp, --sp);
-		put_user((unsigned long) argv, --sp);
+		--sp; put_user((unsigned long) envp, sp);
+		--sp; put_user((unsigned long) argv, sp);
 	}
+
 	put_user(argc,--sp);
 	current->mm->arg_start = (unsigned long) p;
 	while (argc-->0) {
@@ -105,6 +152,7 @@
 	return (unsigned long)sp;
 }
 
+/****************************************************************************/
 
 #ifdef CONFIG_BINFMT_ZFLAT
 
@@ -183,7 +231,7 @@
 	if (buf[3] & EXTRA_FIELD) {
 		ret += 2 + buf[10] + (buf[11] << 8);
 		if (unlikely(LBUFSIZE == ret)) {
-			DBG_FLAT("binfmt_flat: buffer overflow (EXTRA)?\n");
+			DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n");
 			return -ENOEXEC;
 		}
 	}
@@ -191,7 +239,7 @@
 		for (; ret < LBUFSIZE && (buf[ret] != 0); ret++)
 			;
 		if (unlikely(LBUFSIZE == ret)) {
-			DBG_FLAT("binfmt_flat: buffer overflow (ORIG_NAME)?\n");
+			DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n");
 			return -ENOEXEC;
 		}
 	}
@@ -199,7 +247,7 @@
 		for (;  ret < LBUFSIZE && (buf[ret] != 0); ret++)
 			;
 		if (unlikely(LBUFSIZE == ret)) {
-			DBG_FLAT("binfmt_flat: buffer overflow (COMMENT)?\n");
+			DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n");
 			return -ENOEXEC;
 		}
 	}
@@ -243,48 +291,78 @@
 
 #endif /* CONFIG_BINFMT_ZFLAT */
 
+/****************************************************************************/
 
 static unsigned long
-calc_reloc(unsigned long r, unsigned long text_len)
+calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp)
 {
 	unsigned long addr;
-
-	if (r > current->mm->start_brk - current->mm->start_data + text_len) {
-		printk("BINFMT_FLAT: reloc outside program 0x%x (0 - 0x%x), killing!\n",
-				(int) r,(int)(current->mm->start_brk-current->mm->start_code));
-		send_sig(SIGSEGV, current, 0);
-		return(current->mm->start_brk); /* return something safe to write to */
+	int id;
+	unsigned long start_brk;
+	unsigned long start_data;
+	unsigned long text_len;
+	unsigned long start_code;
+
+#ifdef CONFIG_BINFMT_SHARED_FLAT
+	if (r == 0)
+		id = curid;	/* Relocs of 0 are always self referring */
+	else {
+		id = (r >> 24) & 0xff;	/* Find ID for this reloc */
+		r &= 0x00ffffff;	/* Trim ID off here */
+	}
+	if (id >= MAX_SHARED_LIBS) {
+		printk("BINFMT_FLAT: reference 0x%x to shared library %d",
+				(unsigned) r, id);
+		goto failed;
+	}
+	if (curid != id) {
+		if (internalp) {
+			printk("BINFMT_FLAT: reloc address 0x%x not in same module "
+					"(%d != %d)", (unsigned) r, curid, id);
+			goto failed;
+		} else if ( ! p->lib_list[id].loaded &&
+				load_flat_shared_library(id, p) > (unsigned long) -4096) {
+			printk("BINFMT_FLAT: failed to load library %d", id);
+			goto failed;
+		}
+		/* Check versioning information (i.e. time stamps) */
+		if (p->lib_list[id].build_date && p->lib_list[curid].build_date &&
+				p->lib_list[curid].build_date < p->lib_list[id].build_date) {
+			printk("BINFMT_FLAT: library %d is younger than %d", id, curid);
+			goto failed;
+		}
 	}
+#else
+	id = 0;
+#endif
 
-	if (r < text_len) {
-		/* In text segment */
-		return r + current->mm->start_code;
-	}
+	start_brk = p->lib_list[id].start_brk;
+	start_data = p->lib_list[id].start_data;
+	start_code = p->lib_list[id].start_code;
+	text_len = p->lib_list[id].text_len;
+
+	if (!flat_reloc_valid(r, start_brk - start_data + text_len)) {
+		printk("BINFMT_FLAT: reloc outside program 0x%x (0 - 0x%x/0x%x)",
+		       (int) r,(int)(start_brk-start_code),(int)text_len);
+		goto failed;
+	}
+
+	if (r < text_len)			/* In text segment */
+		addr = r + start_code;
+	else					/* In data segment */
+		addr = r - text_len + start_data;
 
-	/*
-	 * we allow inclusive ranges here so that programs may do things
-	 * like reference the end of data (_end) without failing these tests
-	 */
-	addr =  r - text_len + current->mm->start_data;
-	if (addr >= current->mm->start_code &&
-			addr <= current->mm->start_code + text_len)
-		return(addr);
-
-	if (addr >= current->mm->start_data &&
-			addr <= current->mm->start_brk)
-		return(addr);
-
-	printk("BINFMT_FLAT: reloc addr outside text/data 0x%x "
-			"code(0x%x - 0x%x) data(0x%x - 0x%x) killing\n", (int) addr,
-			(int) current->mm->start_code,
-			(int) (current->mm->start_code + text_len),
-			(int) current->mm->start_data,
-			(int) current->mm->start_brk);
+	/* Range checked already above so doing the range tests is redundant...*/
+	return(addr);
+
+failed:
+	printk(", killing %s!\n", current->comm);
 	send_sig(SIGSEGV, current, 0);
 
-	return(current->mm->start_brk); /* return something safe to write to */
+	return RELOC_FAILED;
 }
 
+/****************************************************************************/
 
 void old_reloc(unsigned long rl)
 {
@@ -327,26 +405,22 @@
 #endif
 }		
 
+/****************************************************************************/
 
-/*
- * These are the functions used to load flat style executables and shared
- * libraries.  There is no binary dependent code anywhere else.
- */
-
-static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+static int load_flat_file(struct linux_binprm * bprm,
+		struct lib_info *libinfo, int id, unsigned long *extra_stack)
 {
 	struct flat_hdr * hdr;
 	unsigned long textpos = 0, datapos = 0, result;
+	unsigned long realdatastart = 0;
 	unsigned long text_len, data_len, bss_len, stack_len, flags;
-	unsigned long memp = 0, memkasked = 0; /* for finding the brk area */
+	unsigned long memp = 0; /* for finding the brk area */
 	unsigned long extra, rlim;
-	unsigned long p = bprm->p;
 	unsigned long *reloc = 0, *rp;
 	struct inode *inode;
 	int i, rev, relocs = 0;
 	loff_t fpos;
-
-	DBG_FLT("BINFMT_FLAT: Loading file: %x\n", bprm->file);
+	unsigned long start_code, end_code;
 
 	hdr = ((struct flat_hdr *) bprm->buf);		/* exec-header */
 	inode = bprm->file->f_dentry->d_inode;
@@ -355,41 +429,42 @@
 	data_len  = ntohl(hdr->data_end) - ntohl(hdr->data_start);
 	bss_len   = ntohl(hdr->bss_end) - ntohl(hdr->data_end);
 	stack_len = ntohl(hdr->stack_size);
+	if (extra_stack) {
+		stack_len += *extra_stack;
+		*extra_stack = stack_len;
+	}
 	relocs    = ntohl(hdr->reloc_count);
 	flags     = ntohl(hdr->flags);
 	rev       = ntohl(hdr->rev);
 
-	/*
-	 * We have to add the size of our arguments to our stack size
-	 * otherwise it's too easy for users to create stack overflows
-	 * by passing in a huge argument list.  And yes,  we have to be
-	 * pedantic and include space for the argv/envp array as it may have
-	 * a lot of entries.
-	 */
-	#define TOP_OF_ARGS (PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *))
-	stack_len += TOP_OF_ARGS - bprm->p;             /* the strings */
-	stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */
-	stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */
+	if (flags & FLAT_FLAG_KTRACE)
+		printk("BINFMT_FLAT: Loading file: %s\n", bprm->filename);
 
 	if (strncmp(hdr->magic, "bFLT", 4) ||
 			(rev != FLAT_VERSION && rev != OLD_FLAT_VERSION)) {
 		/*
 		 * because a lot of people do not manage to produce good
 		 * flat binaries,  we leave this printk to help them realise
-		 * the problem.  We only print the error if it's 
-		 * not a script file.
+		 * the problem.  We only print the error if its not a script file
 		 */
 		if (strncmp(hdr->magic, "#!", 2))
 			printk("BINFMT_FLAT: bad magic/rev (0x%x, need 0x%x)\n",
 					rev, (int) FLAT_VERSION);
 		return -ENOEXEC;
 	}
+	
+	/* Don't allow old format executables to use shared libraries */
+	if (rev == OLD_FLAT_VERSION && id != 0) {
+		printk("BINFMT_FLAT: shared libraries are not available before rev 0x%x\n",
+				(int) FLAT_VERSION);
+		return -ENOEXEC;
+	}
 
 	/*
 	 * fix up the flags for the older format,  there were all kinds
 	 * of endian hacks,  this only works for the simple cases
 	 */
-	if (rev == OLD_FLAT_VERSION && flags)
+	if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags))
 		flags = FLAT_FLAG_RAM;
 
 #ifndef CONFIG_BINFMT_ZFLAT
@@ -411,15 +486,22 @@
 		return -ENOMEM;
 
 	/* Flush all traces of the currently running executable */
-	result = flush_old_exec(bprm);
-	if (result)
-		return result;
+	if (id == 0) {
+		result = flush_old_exec(bprm);
+		if (result)
+			return result;
+
+		/* OK, This is the point of no return */
+		set_personality(PER_LINUX);
+	}
 
-	/* OK, This is the point of no return */
-	set_personality(PER_LINUX);
+	/*
+	 * calculate the extra space we need to map in
+	 */
+	extra = max(bss_len + stack_len, relocs * sizeof(unsigned long));
 
 	/*
-	 * there are a couple of cases here,  the separate code/data
+	 * there are a couple of cases here,  the seperate code/data
 	 * case,  and then the fully copied to RAM case which lumps
 	 * it all together.
 	 */
@@ -437,26 +519,27 @@
 			if (!textpos)
 				textpos = (unsigned long) -ENOMEM;
 			printk("Unable to mmap process text, errno %d\n", (int)-textpos);
+			return(textpos);
 		}
 
-		extra = max(bss_len + stack_len, relocs * sizeof(unsigned long)),
-
 		down_write(&current->mm->mmap_sem);
-		datapos = do_mmap(0, 0, data_len + extra,
+		realdatastart = do_mmap(0, 0, data_len + extra +
+				MAX_SHARED_LIBS * sizeof(unsigned long),
 				PROT_READ|PROT_WRITE|PROT_EXEC, 0, 0);
 		up_write(&current->mm->mmap_sem);
 
-		if (datapos == 0 || datapos >= (unsigned long)-4096) {
-			if (!datapos)
-				datapos = (unsigned long) -ENOMEM;
+		if (realdatastart == 0 || realdatastart >= (unsigned long)-4096) {
+			if (!realdatastart)
+				realdatastart = (unsigned long) -ENOMEM;
 			printk("Unable to allocate RAM for process data, errno %d\n",
 					(int)-datapos);
 			do_munmap(current->mm, textpos, text_len);
-			return datapos;
+			return realdatastart;
 		}
+		datapos = realdatastart + MAX_SHARED_LIBS * sizeof(unsigned long);
 
 		DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n",
-				data_len + bss_len + stack_len, datapos);
+				(int)(data_len + bss_len + stack_len), (int)datapos);
 
 		fpos = ntohl(hdr->data_start);
 #ifdef CONFIG_BINFMT_ZFLAT
@@ -466,30 +549,24 @@
 		} else
 #endif
 		{
-			result = bprm->file->f_op->read(bprm->file,
-					(char *) datapos, data_len + extra, &fpos);
+			result = bprm->file->f_op->read(bprm->file, (char *) datapos,
+					data_len + (relocs * sizeof(unsigned long)), &fpos);
 		}
 		if (result >= (unsigned long)-4096) {
 			printk("Unable to read data+bss, errno %d\n", (int)-result);
 			do_munmap(current->mm, textpos, text_len);
-			do_munmap(current->mm, datapos, data_len + extra);
+			do_munmap(current->mm, realdatastart, data_len + extra);
 			return result;
 		}
 
 		reloc = (unsigned long *) (datapos+(ntohl(hdr->reloc_start)-text_len));
-		memp = datapos;
-		memkasked = data_len + extra;
+		memp = realdatastart;
 
 	} else {
 
-		/*
-		 * calculate the extra space we need to map in
-		 */
-
-		extra = max(bss_len + stack_len, relocs * sizeof(unsigned long)),
-
 		down_write(&current->mm->mmap_sem);
-		textpos = do_mmap(0, 0, text_len + data_len + extra,
+		textpos = do_mmap(0, 0, text_len + data_len + extra +
+					MAX_SHARED_LIBS * sizeof(unsigned long),
 				PROT_READ | PROT_EXEC | PROT_WRITE, 0, 0);
 		up_write(&current->mm->mmap_sem);
 		if (!textpos  || textpos >= (unsigned long) -4096) {
@@ -497,12 +574,14 @@
 				textpos = (unsigned long) -ENOMEM;
 			printk("Unable to allocate RAM for process text/data, errno %d\n",
 					(int)-textpos);
+			return(textpos);
 		}
 
-		datapos = textpos + ntohl (hdr->data_start);
-		reloc = (unsigned long *) (textpos + ntohl(hdr->reloc_start));
+		realdatastart = textpos + ntohl(hdr->data_start);
+		datapos = realdatastart + MAX_SHARED_LIBS * sizeof(unsigned long);
+		reloc = (unsigned long *) (textpos + ntohl(hdr->reloc_start) +
+				MAX_SHARED_LIBS * sizeof(unsigned long));
 		memp = textpos;
-		memkasked = text_len + data_len + extra;
 
 #ifdef CONFIG_BINFMT_ZFLAT
 		/*
@@ -514,6 +593,8 @@
 					 (text_len + data_len + (relocs * sizeof(unsigned long))
 						  - sizeof (struct flat_hdr)),
 					 0);
+			memmove((void *) datapos, (void *) realdatastart,
+					data_len + (relocs * sizeof(unsigned long)));
 		} else if (flags & FLAT_FLAG_GZDATA) {
 			fpos = 0;
 			result = bprm->file->f_op->read(bprm->file,
@@ -527,40 +608,64 @@
 		{
 			fpos = 0;
 			result = bprm->file->f_op->read(bprm->file,
-					(char *) textpos, text_len + data_len + extra, &fpos);
+					(char *) textpos, text_len, &fpos);
+			if (result < (unsigned long) -4096) {
+				fpos = ntohl(hdr->data_start);
+				result = bprm->file->f_op->read(bprm->file, (char *) datapos,
+					data_len + (relocs * sizeof(unsigned long)), &fpos);
+			}
 		}
 		if (result >= (unsigned long)-4096) {
 			printk("Unable to read code+data+bss, errno %d\n",(int)-result);
-			do_munmap(current->mm, textpos, text_len + data_len + extra);
+			do_munmap(current->mm, textpos, text_len + data_len + extra +
+				MAX_SHARED_LIBS * sizeof(unsigned long));
 			return result;
 		}
 	}
 
-	DBG_FLT("Mapping is %x, Entry point is %x, data_start is %x\n",
-			textpos, ntohl(hdr->entry), ntohl(hdr->data_start));
+	if (flags & FLAT_FLAG_KTRACE)
+		printk("Mapping is %x, Entry point is %x, data_start is %x\n",
+			(int)textpos, 0x00ffffff&ntohl(hdr->entry), ntohl(hdr->data_start));
+
+	/* The main program needs a little extra setup in the task structure */
+	start_code = textpos + sizeof (struct flat_hdr);
+	end_code = textpos + text_len;
+	if (id == 0) {
+		current->mm->start_code = start_code;
+		current->mm->end_code = end_code;
+		current->mm->start_data = datapos;
+		current->mm->end_data = datapos + data_len;
+		/*
+		 * set up the brk stuff, uses any slack left in data/bss/stack
+		 * allocation.  We put the brk after the bss (between the bss
+		 * and stack) like other platforms.
+		 */
+		current->mm->start_brk = datapos + data_len + bss_len;
+		current->mm->brk = (current->mm->start_brk + 3) & ~3;
+		current->mm->context.end_brk = memp + ksize((void *) memp) - stack_len;
+		current->mm->rss = 0;
+	}
 
-	current->mm->start_code = textpos + sizeof (struct flat_hdr);
-	current->mm->end_code = textpos + text_len;
-	current->mm->start_data = datapos;
-	current->mm->end_data = datapos + data_len;
-	/*
-	 *	set up the brk stuff (uses any slack left in data/bss/stack allocation
-	 *	We put the brk after the bss (between the bss and stack) like other
-	 *	platforms.
-	 */
-	current->mm->start_brk = datapos + data_len + bss_len;
-	current->mm->brk = (current->mm->start_brk + 3) & ~3;
-	current->mm->context.end_brk = memp + ksize((void *) memp) - stack_len;
-	current->mm->rss = 0;
-
-	DBG_FLT("Load %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n",
-		bprm->filename,
-		(int) current->mm->start_code, (int) current->mm->end_code,
-		(int) current->mm->start_data, (int) current->mm->end_data,
-		(int) current->mm->end_data, (int) current->mm->brk);
+	if (flags & FLAT_FLAG_KTRACE)
+		printk("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n",
+			id ? "Lib" : "Load", bprm->filename,
+			(int) start_code, (int) end_code,
+			(int) datapos,
+			(int) (datapos + data_len),
+			(int) (datapos + data_len),
+			(int) (((datapos + data_len + bss_len) + 3) & ~3));
 
 	text_len -= sizeof(struct flat_hdr); /* the real code len */
 
+	/* Store the current module values into the global library structure */
+	libinfo->lib_list[id].start_code = start_code;
+	libinfo->lib_list[id].start_data = datapos;
+	libinfo->lib_list[id].start_brk = datapos + data_len + bss_len;
+	libinfo->lib_list[id].text_len = text_len;
+	libinfo->lib_list[id].loaded = 1;
+	libinfo->lib_list[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos;
+	libinfo->lib_list[id].build_date = ntohl(hdr->build_date);
+	
 	/*
 	 * We just load the allocations into some temporary memory to
 	 * help simplify all this mumbo jumbo
@@ -573,10 +678,16 @@
 	 * really an offset into the image which contains an offset into the
 	 * image.
 	 */
-	
 	if (flags & FLAT_FLAG_GOTPIC) {
-		for (rp = (unsigned long *)datapos; *rp != 0xffffffff; rp++)
-			*rp = calc_reloc(*rp, text_len);
+		for (rp = (unsigned long *)datapos; *rp != 0xffffffff; rp++) {
+			unsigned long addr;
+			if (*rp) {
+				addr = calc_reloc(*rp, libinfo, id, 0);
+				if (addr == RELOC_FAILED)
+					return -ENOEXEC;
+				*rp = addr;
+			}
+		}
 	}
 
 	/*
@@ -590,63 +701,172 @@
 	 * reference to be statically initialised to _stext (I've moved
 	 * __start to address 4 so that is okay).
 	 */
-
 	if (rev > OLD_FLAT_VERSION) {
 		for (i=0; i < relocs; i++) {
-			unsigned long addr;
+			unsigned long addr, relval;
 
 			/* Get the address of the pointer to be
 			   relocated (of course, the address has to be
 			   relocated first).  */
-			rp = (unsigned long *) calc_reloc(ntohl(reloc[i]), text_len);
+			relval = ntohl(reloc[i]);
+			addr = flat_get_relocate_addr(relval);
+			rp = (unsigned long *) calc_reloc(addr, libinfo, id, 1);
+			if (rp == (unsigned long *)RELOC_FAILED)
+				return -ENOEXEC;
 
 			/* Get the pointer's value.  */
-			addr = get_unaligned (rp);
-
+			addr = flat_get_addr_from_rp(rp, relval);
 			if (addr != 0) {
 				/*
 				 * Do the relocation.  PIC relocs in the data section are
 				 * already in target order
 				 */
-				addr = calc_reloc(
-						(flags & FLAT_FLAG_GOTPIC) ? addr : ntohl(addr),
-						text_len);
+				if ((flags & FLAT_FLAG_GOTPIC) == 0)
+					addr = ntohl(addr);
+				addr = calc_reloc(addr, libinfo, id, 0);
+				if (addr == RELOC_FAILED)
+					return -ENOEXEC;
+
 				/* Write back the relocated pointer.  */
-				put_unaligned (addr, rp);
+				flat_put_addr_at_rp(rp, addr, relval);
 			}
 		}
 	} else {
 		for (i=0; i < relocs; i++)
 			old_reloc(ntohl(reloc[i]));
 	}
+	
+	flush_icache_range(start_code, end_code);
 
 	/* zero the BSS,  BRK and stack areas */
 	memset((void*)(datapos + data_len), 0, bss_len + 
-			(current->mm->context.end_brk - current->mm->start_brk) +
+			(memp + ksize((void *) memp) - stack_len -	/* end brk */
+			libinfo->lib_list[id].start_brk) +		/* start brk */
 			stack_len);
 
+	return 0;
+}
+
+
+/****************************************************************************/
+#ifdef CONFIG_BINFMT_SHARED_FLAT
+
+/*
+ * Load a shared library into memory.  The library gets its own data
+ * segment (including bss) but not argv/argc/environ.
+ */
+
+static int load_flat_shared_library(int id, struct lib_info *libs)
+{
+	struct linux_binprm bprm;
+	int res;
+	char buf[16];
+
+	/* Create the file name */
+	sprintf(buf, "/lib/lib%d.so", id);
+
+	/* Open the file up */
+	bprm.filename = buf;
+	bprm.file = open_exec(bprm.filename);
+	res = PTR_ERR(bprm.file);
+	if (IS_ERR(bprm.file))
+		return res;
+
+	res = prepare_binprm(&bprm);
+
+	if (res <= (unsigned long)-4096)
+		res = load_flat_file(&bprm, libs, id, NULL);
+	if (bprm.file) {
+		allow_write_access(bprm.file);
+		fput(bprm.file);
+		bprm.file = NULL;
+	}
+	return(res);
+}
+
+#endif /* CONFIG_BINFMT_SHARED_FLAT */
+/****************************************************************************/
+
+/*
+ * These are the functions used to load flat style executables and shared
+ * libraries.  There is no binary dependent code anywhere else.
+ */
+
+static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+{
+	struct lib_info libinfo;
+	unsigned long p = bprm->p;
+	unsigned long stack_len;
+	unsigned long start_addr;
+	unsigned long *sp;
+	int res;
+	int i, j;
+
+	memset(&libinfo, 0, sizeof(libinfo));
+	/*
+	 * We have to add the size of our arguments to our stack size
+	 * otherwise it's too easy for users to create stack overflows
+	 * by passing in a huge argument list.  And yes,  we have to be
+	 * pedantic and include space for the argv/envp array as it may have
+	 * a lot of entries.
+	 */
+#define TOP_OF_ARGS (PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *))
+	stack_len = TOP_OF_ARGS - bprm->p;             /* the strings */
+	stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */
+	stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */
+
+	
+	res = load_flat_file(bprm, &libinfo, 0, &stack_len);
+	if (res > (unsigned long)-4096)
+		return res;
+	
+	/* Update data segment pointers for all libraries */
+	for (i=0; i<MAX_SHARED_LIBS; i++)
+		if (libinfo.lib_list[i].loaded)
+			for (j=0; j<MAX_SHARED_LIBS; j++)
+				(-(j+1))[(unsigned long *)(libinfo.lib_list[i].start_data)] =
+					(libinfo.lib_list[j].loaded)?
+						libinfo.lib_list[j].start_data:UNLOADED_LIB;
+
 	compute_creds(bprm);
  	current->flags &= ~PF_FORKNOEXEC;
 
-	flush_icache_range(current->mm->start_code, current->mm->end_code);
-
 	set_binfmt(&flat_format);
 
 	p = ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4;
-	DBG_FLT("p=%x\n", p);
+	DBG_FLT("p=%x\n", (int)p);
 
 	/* copy the arg pages onto the stack, this could be more efficient :-) */
 	for (i = TOP_OF_ARGS - 1; i >= bprm->p; i--)
 		* (char *) --p =
 			((char *) page_address(bprm->page[i/PAGE_SIZE]))[i % PAGE_SIZE];
 
-	current->mm->start_stack = (unsigned long) create_flat_tables(p, bprm);
+	sp = (unsigned long *) create_flat_tables(p, bprm);
+	
+	/* Fake some return addresses to ensure the call chain will
+	 * initialise library in order for us.  We are required to call
+	 * lib 1 first, then 2, ... and finally the main program (id 0).
+	 */
+	start_addr = libinfo.lib_list[0].entry;
 
+#ifdef CONFIG_BINFMT_SHARED_FLAT
+	for (i = MAX_SHARED_LIBS-1; i>0; i--) {
+		if (libinfo.lib_list[i].loaded) {
+			/* Push previos first to call address */
+			--sp;	put_user(start_addr, sp);
+			start_addr = libinfo.lib_list[i].entry;
+		}
+	}
+#endif
+	
+	/* Stash our initial stack pointer into the mm structure */
+	current->mm->start_stack = (unsigned long )sp;
+
+	
 	DBG_FLT("start_thread(regs=0x%x, entry=0x%x, start_stack=0x%x)\n",
-		regs, textpos + ntohl(hdr->entry), current->mm->start_stack);
-	start_thread(regs,
-		     textpos + ntohl(hdr->entry),
-		     current->mm->start_stack);
+		(int)regs, (int)start_addr, (int)current->mm->start_stack);
+	
+	start_thread(regs, start_addr, current->mm->start_stack);
 
 	if (current->ptrace & PT_PTRACED)
 		send_sig(SIGTRAP, current, 0);
@@ -654,10 +874,7 @@
 	return 0;
 }
 
-static int load_flat_library(struct file *file)
-{
-	return(-ENOEXEC);
-}
+/****************************************************************************/
 
 static int __init init_flat_binfmt(void)
 {
@@ -669,5 +886,9 @@
 	unregister_binfmt(&flat_format);
 }
 
+/****************************************************************************/
+
 module_init(init_flat_binfmt);
 module_exit(exit_flat_binfmt);
+
+/****************************************************************************/
diff -urN linux-2.5.74-bk4/fs/buffer.c linux-2.5.74-bk5/fs/buffer.c
--- linux-2.5.74-bk4/fs/buffer.c	2003-07-07 04:56:55.000000000 -0700
+++ linux-2.5.74-bk5/fs/buffer.c	2003-07-07 04:57:15.000000000 -0700
@@ -1454,24 +1454,13 @@
 /*
  * Do async read-ahead on a buffer..
  */
-void
-__breadahead(struct block_device *bdev, sector_t block, int size)
+void __breadahead(struct block_device *bdev, sector_t block, int size)
 {
 	struct buffer_head *bh = __getblk(bdev, block, size);
-	if (!test_set_buffer_locked(bh)) {
-		if (!buffer_uptodate(bh)) {
-			/*
-			 * This eats the bh count from __getblk() and
-			 * unlocks when the read is done.
-			 */
-			bh->b_end_io = end_buffer_io_sync;
-			submit_bh(READ, bh);
-			return;
-		}
-		unlock_buffer(bh);
-	}
+	ll_rw_block(READA, 1, &bh);
 	brelse(bh);
 }
+EXPORT_SYMBOL(__breadahead);
 
 /**
  *  __bread() - reads a specified block and returns the bh
diff -urN linux-2.5.74-bk4/fs/cifs/CHANGES linux-2.5.74-bk5/fs/cifs/CHANGES
--- linux-2.5.74-bk4/fs/cifs/CHANGES	2003-07-02 13:54:44.000000000 -0700
+++ linux-2.5.74-bk5/fs/cifs/CHANGES	2003-07-07 04:57:15.000000000 -0700
@@ -1,3 +1,13 @@
+Version 0.81
+------------
+Finish up CIFS packet digital signing for the default
+NTLM security case. This should help Windows 2003
+network interoperability since it is common for
+packet signing to be required now. Fix statfs (stat -f)
+which recently started returning errors due to 
+invalid value (-1 instead of 0) being set in the
+struct kstatfs f_ffiles field.
+
 Version 0.80
 -----------
 Fix oops on stopping oplock thread when removing cifs when
diff -urN linux-2.5.74-bk4/fs/cifs/Makefile linux-2.5.74-bk5/fs/cifs/Makefile
--- linux-2.5.74-bk4/fs/cifs/Makefile	2003-07-02 13:43:28.000000000 -0700
+++ linux-2.5.74-bk5/fs/cifs/Makefile	2003-07-07 04:57:15.000000000 -0700
@@ -3,4 +3,4 @@
 #
 obj-$(CONFIG_CIFS) += cifs.o
 
-cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o
+cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o
diff -urN linux-2.5.74-bk4/fs/cifs/README linux-2.5.74-bk5/fs/cifs/README
--- linux-2.5.74-bk4/fs/cifs/README	2003-07-02 13:56:33.000000000 -0700
+++ linux-2.5.74-bk5/fs/cifs/README	2003-07-07 04:57:15.000000000 -0700
@@ -1,5 +1,5 @@
-This is the CIFS VFS support for Linux.  It supports many advanced network filesystem
-features such as heirarchical dfs like filesystem, hardlinks, locking and more.
+The CIFS VFS support for Linux supports many advanced network filesystem
+features such as heirarchical dfs like namespace, hardlinks, locking and more.
 It was designed to comply with the SNIA CIFS Technical Reference (which supersedes
 the 1992 X/Open SMB Standard) as well as to perform best practice practical
 interoperability with Windows 2000, Windows XP, Samba and equivalent 
@@ -9,43 +9,65 @@
 
 Build instructions:
 ==================
-Get the kernel source e.g. http://linux.bkbits.net/linux-2.5 or http://www.kernel.org 
-http://cifs.bkbits.net/linux-2.4  
-make menuconfig (or make xconfig)
-select cifs from within the network filesystem choices
-save and exit
-make dep
-make modules  (or "make" if you did not select CIFS VFS to be built as a module)
+For Linux 2.4:
+1a) Get the linux kernel source with cifs vfs already in it
+from bitkeeper via bk://cifs.bkbits.net/linux-2.4
+or
+1b) Get the kernel source (e.g.from http://www.kernel.org)
+and download the cifs vfs source (see the project page
+at http://us1.samba.org/samba/Linux_CIFS_client.html)
+and change directory into the top of the kernel directory
+then patch the kernel (e.g. "patch -p1 < cifs_24.patch") 
+to add the cifs vfs to your kernel configure options if
+it has not already been added (e.g. current SuSE and UL
+users do not need to do not need that patch since the cifs vfs is
+already in the kernel configure menu) and then
+mkdir linux/fs/cifs and then copy the current cifs vfs files from
+the cifs download to your kernel build directory e.g.
+	cp <cifs_download_dir>/fs/cifs/* to <kernel_download_dir>/fs/cifs
+2) make menuconfig (or make xconfig)
+3) select cifs from within the network filesystem choices
+4) save and exit
+5) make dep
+6) make modules (or "make" if CIFS VFS not to be built as a module)
+
+For Linux 2.5:
+1) Download the kernel (e.g. from http://www.kernel.org or from bitkeeper
+at bk://linux.bkbits.net/linux-2.5) and change directory into the top
+of the kernel directory tree (e.g. /usr/src/linux-2.5.73)
+2) make menuconfig (or make xconfig)
+3) select cifs from within the network filesystem choices
+4) save and exit
+5) make
+
 
 Installation instructions:
 =========================
-If you have built the CIFS vfs as module (successfully)you
-simply type "make modules_install" (or if you prefer manually copy the file to
+If you have built the CIFS vfs as module (successfully) simply
+type "make modules_install" (or if you prefer, manually copy the file to
 the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.o).
 
 If you have built the CIFS vfs into the kernel itself, follow the instructions
 for your distribution on how to install a new kernel (usually you
 would simply type "make install").
 
-If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on the
-CIFS VFS web site) copy it to the directory /sbin (or the same directory in which 
-mount.smbfs resides).  Although no helper software is required, the installation
-of mount.cifs is recommended.  Eventually the Samba 3.0 utility program "net" 
+If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on 
+the CIFS VFS web site) copy it to the same directory in which mount.smbfs and 
+similar files reside (usually /sbin).  Although the helper software is required, 
+mount.cifs is recommended.  Eventually the Samba 3.0 utility program "net" 
 may also be helpful since it may someday provide easier mount syntax for users used 
 to Windows e.g.
 	 net use <mount point> <UNC name or cifs URL> 	 
-and there will likely be other helper programs available ala smbmount to provide
-additional optional function in the future.  Note that running Winbind on all
-of your Linux clients is useful in mapping Uids and Gids consistently to the
-proper network user.	
+Note that running Winbind on all of your Linux clients is useful in 
+in mapping Uids and Gids consistently to the proper network user.
 
 Samba Considerations
 ====================
 To get the maximum benefit from the CIFS VFS, we recommend using a server that
-supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or Samba 3.0)
-but the CIFS vfs works fine with a wide variety of CIFS servers.  Note that the
-uid, gid and file permissions will display default values if you do not have
-a server that supports the Unix extensions for CIFS (such as Samba 2.2.3 or
+supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or later or 
+Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers. 
+Note that uid, gid and file permissions will display default values if you do
+not have a server that supports the Unix extensions for CIFS (such as Samba 2.2.3 or
 later).   To enable the Unix CIFS Extensions in the Samba server, add the line:
 	unix extensions = yes
 to your smb.conf file on the server.  Note that the following smb.conf settings are
@@ -81,15 +103,79 @@
 "Netbios-Over-TCP/IP."  Neither of these is likely to be a problem as most servers
 support this.  IPv6 support is planned for the future.  
 
+CIFS VFS Mount Options
+======================
+A partial list of the supported mount options follows:
+  user		The user name to use when trying to establish
+		the CIFS session.
+  password	The user password.  If the mount helper is
+		installed, the user will be prompted for password
+		if it is not supplied.
+  ip		The ip address of the target server
+  unc		The target server Universal Network Name (export) to 
+		mount.	
+  domain	Set the SMB/CIFS workgroup name prepended to the
+		username during CIFS session establishment
+  uid           If CIFS Unix extensions are not supported by the server
+                this overrides the default uid for inodes.
+  gid		If CIFS Unix extensions are not supported by the server
+		this overrides the default gid for inodes.
+  file_mode     If CIFS Unix extensions are not supported by the server
+		this overrides the default mode for file inodes.
+  dir_mode      If CIFS Unix extensions are not supported by the server 
+		this overrides the default mode for directory inodes.
+  port		attempt to contact the server on this tcp port, before
+		trying the usual ports (port 445, then 139).
+  rsize		default read size
+  wsize		default write size
+  rw		mount the network share read-write (note that the
+		server may still consider the share read-only)
+  ro		mount network share read-only
+  version	used to distinguish different versions of the
+		mount helper utility (not typically needed)
+
 Misc /proc/fs/cifs Flags and Debug Info
 =======================================
-Various experimental features and tracing can be enabled by changing flags in /proc/fs/cifs (after
-the cifs module has been installed or built into the kernel, e.g. insmod cifs).  To enable
-a feature you can set it to 1 e.g. to enable tracing to the kernel message log you can do
-"echo 1 > /proc/fs/cifs/cifsFYI" and "echo 1 > /proc/fs/cifs/traceSMB"
-Also note that "cat /proc/fs/cifs/DebugData" will display some information about the currently
-active sessions and the shares that are mounted. Currently the ntlmv2 enablement and packet
-signing will not work since they the implementation is not quite complete, so do not enable
+Informational pseudo-files:
+  DebugData		Displays information about active CIFS sessions
+  SimultaneousOps       Counter which holds maximum number of
+			simultaneous outstanding SMB/CIFS requests.
+  Stats			Lists summary resource usage information
+
+Configuration pseudo-files:
+  MultiuserMount	If set to one, more than one CIFS session to 
+			the same server ip address can be established
+			if more than one uid accesses the same mount
+			point and if the uids user/password mapping
+			information is available. (default is 0)
+  PacketSigningEnabled  If set to one, cifs packet signing is enabled
+			(default 0)
+  cifsFYI		If set to one, additional debug information is
+			logged to the system error log. (default 0)
+  ExtendedSecurity	If set to one, SPNEGO session establishment
+			is allowed which enables more advanced 
+			secure CIFS session establishment (default 0)
+  NTLMV2Enabled		If set to one, more secure password hashes
+			are used when the server supports them and
+			when kerberos is not negotiated (default 0)
+  traceSMB		If set to one, debug information is logged to the
+			system error log with the start of smb requests
+			and responses (default 0)
+  LookupCacheEnable     If set to one, inode information is kept cached
+			for one second improving performance of lookups
+			(default 1)
+  OplockEnabled		If set to one, safe distributed caching enabled.
+
+These experimental features and tracing can be enabled by changing flags in /proc/fs/cifs
+(after the cifs module has been installed or built into the kernel, e.g. insmod cifs). 
+To enable a feature set it to 1 e.g. to enable tracing to the kernel message log
+type:
+	echo 1 > /proc/fs/cifs/cifsFYI
+and for more extensive tracing including the start of smb requests and responses
+	echo 1 > /proc/fs/cifs/traceSMB
+Also note that "cat /proc/fs/cifs/DebugData" will display some information about the
+active sessions and the shares that are mounted. NTLMv2 enablement and packet
+signing will not work since they the implementation is not quite complete. Do not enable
 these flags unless you are doing specific testing.  Enabling extended security works to
 Windows 2000 Workstations and XP but not to Windows 2000 server or Samba since it does not
 usually send "raw NTLMSSP" (instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which
diff -urN linux-2.5.74-bk4/fs/cifs/TODO linux-2.5.74-bk5/fs/cifs/TODO
--- linux-2.5.74-bk4/fs/cifs/TODO	2003-07-02 13:56:41.000000000 -0700
+++ linux-2.5.74-bk5/fs/cifs/TODO	2003-07-07 04:57:15.000000000 -0700
@@ -1,4 +1,4 @@
-version 0.6.5 February 15, 2003
+version 0.8.1 July 4th, 2003
 
 A Partial List of Known Problems and Missing Features
 =====================================================
@@ -19,10 +19,9 @@
 
 e) NTLMv2 authentication and MD5-HMAC signing SMB PDUs - (mostly implemented)
 	signing necessary for some Windows 2003 servers in domain 
-	controller mode.
+	mode.
 
-f) oplock support (ie safe CIFS distributed file caching) is not quite complete.
-In addition Directory entry caching relies on a 1 second timer, rather than 
+f) Directory entry caching relies on a 1 second timer, rather than 
 using FindNotify or equivalent.  - (started)
 
 g) There may be a few additional changes that could be done to take advantage
@@ -47,15 +46,16 @@
 n) send oplock break response when sent (oplock currently disabled in
 /proc/fs/cifs)
 
-o) remove calls to set end of file by name when we already have file open
-(use the existing handle since some servers only support that and it
-reduces the oplock breaks coming from windows).  Piggyback identical
+o) reduces the oplock breaks coming from windows).  Piggyback identical
 file opens on top of each other by incrementing reference count rather
 than resending (helps reduce server resource utilization and avoid
 spurious oplock breaks).
 
+p) Improve performance of readpages by sending more than one read
+at a time when 8 pages or more are requested.
 
-KNOWN BUGS (updated May 16, 2003)
+
+KNOWN BUGS (updated July 4th, 2003)
 ====================================
 1) existing symbolic links (Windows reparse points) are recognized but
 can not be created remotely. They are implemented for Samba and those that
@@ -74,8 +74,8 @@
 1) check out max path names and max path name components against various server
 types.
 
-2) Run dbench
+2) Run dbench. Modify file portion of ltp so it can run against a mounted network
+share and run it against cifs vfs.
 
-3) Finish high stress fsx testing on SMP clients
+3) Additional performance testing and optimization using iozone and similar tools.
 
-4) Additional performance testing and optimization
diff -urN linux-2.5.74-bk4/fs/cifs/cifs_unicode.c linux-2.5.74-bk5/fs/cifs/cifs_unicode.c
--- linux-2.5.74-bk4/fs/cifs/cifs_unicode.c	2003-07-02 13:58:29.000000000 -0700
+++ linux-2.5.74-bk5/fs/cifs/cifs_unicode.c	2003-07-07 04:57:15.000000000 -0700
@@ -34,7 +34,7 @@
 void
 toUpper(const struct nls_table *n, char *mixed_string)
 {
-	int i;
+	unsigned int i;
 	char temp;
 
 	for (i = 0; i < strlen(mixed_string); i++) {
diff -urN linux-2.5.74-bk4/fs/cifs/cifsencrypt.c linux-2.5.74-bk5/fs/cifs/cifsencrypt.c
--- linux-2.5.74-bk4/fs/cifs/cifsencrypt.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.5.74-bk5/fs/cifs/cifsencrypt.c	2003-07-07 04:57:15.000000000 -0700
@@ -0,0 +1,140 @@
+/*
+ *   fs/cifs/cifsencrypt.c
+ *
+ *   Copyright (c) International Business Machines  Corp., 2003
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/fs.h>
+#include "cifspdu.h"
+#include "cifsglob.h" 
+#include "cifs_debug.h"
+#include "md5.h"
+
+/* Calculate and return the CIFS signature based on the mac key and the smb pdu */
+/* the 16 byte signature must be allocated by the caller  */
+/* Note we only use the 1st eight bytes */
+/* Note that the smb header signature field on input contains the  
+	sequence number before this function is called */
+
+extern void mdfour(unsigned char *out, unsigned char *in, int n);
+extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
+	
+static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * key, char * signature)
+{
+	struct	MD5Context context;
+
+	if((cifs_pdu == NULL) || (signature == NULL))
+		return -EINVAL;
+
+	MD5Init(&context);
+	MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
+	MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length);
+	MD5Final(signature,&context);
+	return 0;
+}
+
+int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses,
+	__u32 * pexpected_response_sequence_number)
+{
+	int rc = 0;
+	char smb_signature[20];
+
+	/* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */
+	/* BB remember to add code to save expected sequence number in midQ entry BB */
+
+	if((cifs_pdu == NULL) || (ses == NULL))
+		return -EINVAL;
+
+	if((le32_to_cpu(cifs_pdu->Flags2) & SMBFLG2_SECURITY_SIGNATURE) == 0) 
+		return rc;
+
+	write_lock(&GlobalMid_Lock);
+	cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number);
+	cifs_pdu->Signature.Sequence.Reserved = 0;
+	
+	*pexpected_response_sequence_number = ses->sequence_number++;
+	ses->sequence_number++;
+	write_unlock(&GlobalMid_Lock);
+
+	rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature);
+	if(rc)
+                memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
+	else
+		memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
+
+	return rc;
+}
+
+int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key,
+	__u32 expected_sequence_number)
+{
+	unsigned int rc;
+	char server_response_sig[8];
+	char what_we_think_sig_should_be[20];
+
+        if((cifs_pdu == NULL) || (mac_key == NULL))
+                return -EINVAL;
+
+	if (cifs_pdu->Command == SMB_COM_NEGOTIATE)
+		return 0;
+
+	/* BB what if signatures are supposed to be on for session but server does not
+		send one? BB */
+	/* BB also do not verify oplock breaks for signature */
+	
+	/* Do not need to verify session setups with signature "BSRSPYL "  */
+	if(memcmp(cifs_pdu->Signature.SecuritySignature,"BSRSPYL ",8)==0)
+		cFYI(1,("dummy signature received for smb command 0x%x",cifs_pdu->Command));
+
+	expected_sequence_number = cpu_to_le32(expected_sequence_number);
+
+	/* save off the origiginal signature so we can modify the smb and check
+		its signature against what the server sent */
+	memcpy(server_response_sig,cifs_pdu->Signature.SecuritySignature,8);
+
+        cifs_pdu->Signature.Sequence.SequenceNumber = expected_sequence_number;
+        cifs_pdu->Signature.Sequence.Reserved = 0;
+
+        rc = cifs_calculate_signature(cifs_pdu, mac_key,
+		what_we_think_sig_should_be);
+
+	if(rc)
+		return rc;
+
+	
+/*	cifs_dump_mem("what we think it should be: ",what_we_think_sig_should_be,16); */
+
+	if(memcmp(server_response_sig, what_we_think_sig_should_be, 8))
+		return -EACCES;
+	else
+		return 0;
+
+}
+
+/* We fill in key by putting in 40 byte array which was allocated by caller */
+int cifs_calculate_mac_key(char * key, const char * rn, const char * password)
+{
+	char temp_key[16];
+	if ((key == NULL) || (rn == NULL) || (password == NULL))
+		return -EINVAL;
+
+	E_md4hash(password, temp_key);  /* BB may have to do another md4 of it */
+	mdfour(key,temp_key,16);
+	memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE);
+	return 0;
+} 
diff -urN linux-2.5.74-bk4/fs/cifs/cifsfs.c linux-2.5.74-bk5/fs/cifs/cifsfs.c
--- linux-2.5.74-bk4/fs/cifs/cifsfs.c	2003-07-07 04:56:55.000000000 -0700
+++ linux-2.5.74-bk5/fs/cifs/cifsfs.c	2003-07-07 04:57:15.000000000 -0700
@@ -165,7 +165,7 @@
 					   able to support more than this, but best to be safe
 					   since Win2k and others can not handle very long filenames */
 	buf->f_files = 0;	/* undefined */
-	buf->f_ffree = -1;	/* unlimited */
+	buf->f_ffree = 0;	/* unlimited */
 
 	rc = CIFSSMBQFSInfo(xid, pTcon, buf, cifs_sb->local_nls);
 
diff -urN linux-2.5.74-bk4/fs/cifs/cifsfs.h linux-2.5.74-bk5/fs/cifs/cifsfs.h
--- linux-2.5.74-bk4/fs/cifs/cifsfs.h	2003-07-07 04:56:55.000000000 -0700
+++ linux-2.5.74-bk5/fs/cifs/cifsfs.h	2003-07-07 04:57:15.000000000 -0700
@@ -88,5 +88,9 @@
 extern int cifs_readlink(struct dentry *direntry, char *buffer, int buflen);
 extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
 			const char *symname);
-
+extern int	cifs_removexattr(struct dentry *, const char *);
+extern int 	cifs_setxattr(struct dentry *, const char *, const void *,
+			 size_t, int);
+extern ssize_t	cifs_getxattr(struct dentry *, const char *, void *, size_t);
+extern ssize_t	cifs_listxattr(struct dentry *, char *, size_t);
 #endif				/* _CIFSSMB_H */
diff -urN linux-2.5.74-bk4/fs/cifs/cifsglob.h linux-2.5.74-bk5/fs/cifs/cifsglob.h
--- linux-2.5.74-bk4/fs/cifs/cifsglob.h	2003-07-02 13:42:44.000000000 -0700
+++ linux-2.5.74-bk5/fs/cifs/cifsglob.h	2003-07-07 04:57:15.000000000 -0700
@@ -149,7 +149,9 @@
 	struct TCP_Server_Info *server;	/* pointer to server info */
 	atomic_t inUse;		/* # of CURRENT users of this ses */
 	enum statusEnum status;
+	__u32 sequence_number;  /* needed for CIFS PDU signature */
 	__u16 ipc_tid;		/* special tid for connection to IPC share */
+	char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16];	
 	char *serverOS;		/* name of operating system underlying the server */
 	char *serverNOS;	/* name of network operating system that the server is running */
 	char *serverDomain;	/* security realm of server */
@@ -249,6 +251,7 @@
 	struct list_head qhead;	/* mids waiting on reply from this server */
 	__u16 mid;		/* multiplex id */
 	__u16 pid;		/* process id */
+	__u32 sequence_number;  /* for CIFS signing */
 	__u16 command;		/* smb command code */
 	struct timeval when_sent;	/* time when smb sent */
 	struct cifsSesInfo *ses;	/* smb was sent to this server */
diff -urN linux-2.5.74-bk4/fs/cifs/cifspdu.h linux-2.5.74-bk5/fs/cifs/cifspdu.h
--- linux-2.5.74-bk4/fs/cifs/cifspdu.h	2003-07-02 13:54:31.000000000 -0700
+++ linux-2.5.74-bk5/fs/cifs/cifspdu.h	2003-07-07 04:57:15.000000000 -0700
@@ -307,7 +307,13 @@
 	__u8 Flags;
 	__u16 Flags2;		/* note: le */
 	__u16 PidHigh;		/* note: le */
-	__u8 SecuritySignature[8];	/* note le */
+	union {
+		struct {
+			__u32 SequenceNumber;  /* le */
+			__u32 Reserved; /* zero */
+		} Sequence;
+		__u8 SecuritySignature[8];	/* le */
+	} Signature;
 	__u8 pad[2];
 	__u16 Tid;
 	__u16 Pid;		/* note: le */
diff -urN linux-2.5.74-bk4/fs/cifs/cifsproto.h linux-2.5.74-bk5/fs/cifs/cifsproto.h
--- linux-2.5.74-bk4/fs/cifs/cifsproto.h	2003-07-02 13:40:19.000000000 -0700
+++ linux-2.5.74-bk5/fs/cifs/cifsproto.h	2003-07-07 04:57:15.000000000 -0700
@@ -79,8 +79,7 @@
 			struct nls_table * nls_info);
 extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses);
 extern int CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
-			char *session_key, char *ntlm_session_key,
-			const struct nls_table *);
+			char *ntlm_session_key, const struct nls_table *);
 extern int CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 			char *SecurityBlob,int SecurityBlobLength,
 			const struct nls_table *);
@@ -226,6 +225,11 @@
 extern int cifs_demultiplex_thread(struct TCP_Server_Info *);
 extern int cifs_reconnect(struct TCP_Server_Info *server);
 
+extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *);
+extern int cifs_verify_signature(const struct smb_hdr *, const char * mac_key,
+	__u32 expected_sequence_number);
+extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass);
+
 /* BB routines below not implemented yet BB */
 
 extern int CIFSBuildServerList(int xid, char *serverBufferList,
diff -urN linux-2.5.74-bk4/fs/cifs/cifssmb.c linux-2.5.74-bk5/fs/cifs/cifssmb.c
--- linux-2.5.74-bk4/fs/cifs/cifssmb.c	2003-07-02 13:43:24.000000000 -0700
+++ linux-2.5.74-bk5/fs/cifs/cifssmb.c	2003-07-07 04:57:15.000000000 -0700
@@ -106,9 +106,6 @@
 	pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
 	if (extended_security)
 		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-	if (sign_CIFS_PDUs) {
-		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-	}
 
 	pSMB->ByteCount = strlen(protocols[0].name) + 1;
 	strncpy(pSMB->DialectsArray, protocols[0].name, 30);	
@@ -260,10 +257,13 @@
 		up(&ses->sesSem);
 		return -EBUSY;
 	}
-	if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
 	rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, 0 /* no tcon anymore */,
 		 (void **) &pSMB, (void **) &smb_buffer_response);
+
+        if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+                pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
 	if (rc) {
 		up(&ses->sesSem);
 		return rc;
@@ -1657,8 +1657,6 @@
 	if (ses->capabilities & CAP_DFS) {
 		pSMB->hdr.Flags2 |= SMBFLG2_DFS;
 	}
-	if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
 	if (ses->capabilities & CAP_UNICODE) {
 		pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
diff -urN linux-2.5.74-bk4/fs/cifs/connect.c linux-2.5.74-bk5/fs/cifs/connect.c
--- linux-2.5.74-bk4/fs/cifs/connect.c	2003-07-02 13:55:50.000000000 -0700
+++ linux-2.5.74-bk5/fs/cifs/connect.c	2003-07-07 04:57:15.000000000 -0700
@@ -200,7 +200,7 @@
 			continue;
 		}
 		pdu_length = 4 + ntohl(smb_buffer->smb_buf_length);
-		cFYI(1, ("Peek length rcvd: %d with smb length: %d", length, pdu_length));	/* BB */
+		cFYI(1, ("Peek length rcvd: %d with smb length: %d", length, pdu_length));
 
 		temp = (char *) smb_buffer;
 		if (length > 3) {
@@ -332,8 +332,9 @@
 		kfree(server);
 	} else	/* BB need to more gracefully handle the rare negative session 
 			   response case because response will be still outstanding */
-		cERROR(1, ("There are still active MIDs in queue and we are exiting but we can not delete mid_q_entries or TCP_Server_Info structure due to pending requests MEMORY LEAK!!"));	/* BB wake up waitors, and/or wait and/or free stale mids and try again? BB */
-/* BB Need to fix bug in error path above - perhaps wait until smb requests
+		cERROR(1, ("Active MIDs in queue while exiting - can not delete mid_q_entries or TCP_Server_Info structure due to pending requests MEMORY LEAK!!"));
+	/* BB wake up waitors, and/or wait and/or free stale mids and try again? BB */
+	/* BB Need to fix bug in error path above - perhaps wait until smb requests
    time out and then free the tcp per server struct BB */
 	read_unlock(&GlobalSMBSeslock);
 
@@ -641,6 +642,7 @@
 	if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */
 		rc = CIFSSMBNegotiate(xid, pSesInfo);
 	pSesInfo->capabilities = pSesInfo->server->capabilities;
+	pSesInfo->sequence_number = 0;
 	if (!rc) {
 		cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
 			pSesInfo->server->secMode,
@@ -671,6 +673,8 @@
 					SMBNTencrypt(pSesInfo->password_with_pad,
 						pSesInfo->server->cryptKey,ntlm_session_key);
 
+				/* BB add call to save MAC key here BB */
+
 				/* for better security the weaker lanman hash not sent 
 				   in AuthSessSetup so why bother calculating it */
 				/* toUpper(nls_info,
@@ -689,10 +693,10 @@
 			SMBNTencrypt(pSesInfo->password_with_pad,
 				pSesInfo->server->cryptKey,
 				ntlm_session_key);
+
+			cifs_calculate_mac_key(pSesInfo->mac_signing_key, ntlm_session_key, pSesInfo->password_with_pad);
 			rc = CIFSSessSetup(xid, pSesInfo,
-				session_key,
-				ntlm_session_key,
-				nls_info);
+				ntlm_session_key, nls_info);
 		}
 		if (rc) {
 			cERROR(1,("Send error in SessSetup = %d",rc));
@@ -1024,7 +1028,6 @@
 int
 CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 	      char session_key[CIFS_SESSION_KEY_SIZE],
-	      char session_key2[CIFS_SESSION_KEY_SIZE],
 	      const struct nls_table *nls_codepage)
 {
 	struct smb_hdr *smb_buffer;
@@ -1081,9 +1084,9 @@
 	pSMB->req_no_secext.CaseSensitivePasswordLength =
 	    cpu_to_le16(CIFS_SESSION_KEY_SIZE);
 	bcc_ptr = pByteArea(smb_buffer);
-	/* memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
+	/* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE);
 	   bcc_ptr += CIFS_SESSION_KEY_SIZE; */
-	memcpy(bcc_ptr, (char *) session_key2, CIFS_SESSION_KEY_SIZE);
+	memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
 	bcc_ptr += CIFS_SESSION_KEY_SIZE;
 
 	if (ses->capabilities & CAP_UNICODE) {
@@ -1094,7 +1097,7 @@
 		if(user == NULL)
 			bytes_returned = 0; /* skill null user */
         else
-		    bytes_returned =
+		bytes_returned =
 		        cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
 		bcc_ptr += 2 * bytes_returned;	/* convert num 16 bit words to bytes */
 		bcc_ptr += 2;	/* trailing null */
diff -urN linux-2.5.74-bk4/fs/cifs/inode.c linux-2.5.74-bk5/fs/cifs/inode.c
--- linux-2.5.74-bk4/fs/cifs/inode.c	2003-07-02 13:40:08.000000000 -0700
+++ linux-2.5.74-bk5/fs/cifs/inode.c	2003-07-07 04:57:15.000000000 -0700
@@ -635,9 +635,9 @@
 	struct cifsFileInfo *open_file = NULL;
 	FILE_BASIC_INFO time_buf;
 	int set_time = FALSE;
-	__u64 mode = 0xFFFFFFFFFFFFFFFF;
-	__u64 uid = 0xFFFFFFFFFFFFFFFF;
-	__u64 gid = 0xFFFFFFFFFFFFFFFF;
+	__u64 mode = 0xFFFFFFFFFFFFFFFFULL;
+	__u64 uid = 0xFFFFFFFFFFFFFFFFULL;
+	__u64 gid = 0xFFFFFFFFFFFFFFFFULL;
 	struct cifsInodeInfo *cifsInode;
 
 	xid = GetXid();
diff -urN linux-2.5.74-bk4/fs/cifs/smbdes.c linux-2.5.74-bk5/fs/cifs/smbdes.c
--- linux-2.5.74-bk4/fs/cifs/smbdes.c	2003-07-02 13:47:36.000000000 -0700
+++ linux-2.5.74-bk5/fs/cifs/smbdes.c	2003-07-07 04:57:15.000000000 -0700
@@ -399,7 +399,7 @@
 		s_box[ind] = s_box[j];
 		s_box[j] = tc;
 	}
-	for (ind = 0; ind < (val ? 516 : 16); ind++) {
+	for (ind = 0; ind < val; ind++) {
 		unsigned char tc;
 		unsigned char t;
 
diff -urN linux-2.5.74-bk4/fs/cifs/smbencrypt.c linux-2.5.74-bk5/fs/cifs/smbencrypt.c
--- linux-2.5.74-bk4/fs/cifs/smbencrypt.c	2003-07-02 13:47:30.000000000 -0700
+++ linux-2.5.74-bk5/fs/cifs/smbencrypt.c	2003-07-07 04:57:16.000000000 -0700
@@ -5,7 +5,8 @@
    Copyright (C) Andrew Tridgell 1992-2000
    Copyright (C) Luke Kenneth Casson Leighton 1996-2000
    Modified by Jeremy Allison 1995.
-   Modified by Steve French (sfrench@us.ibm.com) 2002
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
+   Modified by Steve French (sfrench@us.ibm.com) 2002-2003
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -97,13 +98,15 @@
 	E_P16(p14, p21);
 
 	SMBOWFencrypt(p21, c8, p24);
-
+	
 #ifdef DEBUG_PASSWORD
 	DEBUG(100, ("SMBencrypt: lm#, challenge, response\n"));
 	dump_data(100, (char *) p21, 16);
 	dump_data(100, (char *) c8, 8);
 	dump_data(100, (char *) p24, 24);
 #endif
+	memset(p14,0,15);
+	memset(p21,0,21);
 }
 
 /* Routines for Windows NT MD4 Hash functions. */
@@ -161,6 +164,7 @@
 	len = _my_wcslen(wpwd) * sizeof (__u16);
 
 	mdfour(p16, (unsigned char *) wpwd, len);
+	memset(wpwd,0,129 * 2);
 }
 
 /* Does both the NT and LM owfs of a user's password */
@@ -222,7 +226,7 @@
 	/* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER);
 	   push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */
 
-	/* do not think it is supposed to be uppercased */
+	/* BB user and domain may need to be uppercased */
 	user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage);
 	domain_l = cifs_strtoUCS(dom_u, domain_n, 511, nls_codepage);
 
@@ -297,8 +301,52 @@
 #endif
 }
 
-int
-make_oem_passwd_hash(char data[516], const char *passwd,
+/* Does the md5 encryption from the NT hash for NTLMv2. */
+void
+SMBOWFencrypt_ntv2(const unsigned char kr[16],
+                   const struct data_blob * srv_chal,
+                   const struct data_blob * cli_chal, unsigned char resp_buf[16])
+{
+        struct HMACMD5Context ctx;
+
+        hmac_md5_init_limK_to_64(kr, 16, &ctx);
+        hmac_md5_update(srv_chal->data, srv_chal->length, &ctx);
+        hmac_md5_update(cli_chal->data, cli_chal->length, &ctx);
+        hmac_md5_final(resp_buf, &ctx);
+
+#ifdef DEBUG_PASSWORD
+        DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, cli_chal, resp_buf\n"));
+        dump_data(100, srv_chal->data, srv_chal->length);
+        dump_data(100, cli_chal->data, cli_chal->length);
+        dump_data(100, resp_buf, 16);
+#endif
+}
+
+static struct data_blob LMv2_generate_response(const unsigned char ntlm_v2_hash[16],
+                                        const struct data_blob * server_chal)
+{
+        unsigned char lmv2_response[16];
+	struct data_blob lmv2_client_data/* = data_blob(NULL, 8)*/; /* BB Fix BB */
+        struct data_blob final_response /* = data_blob(NULL, 24)*/; /* BB Fix BB */
+
+        /* LMv2 */
+        /* client-supplied random data */
+        get_random_bytes(lmv2_client_data.data, lmv2_client_data.length);
+        /* Given that data, and the challenge from the server, generate a response */
+        SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, &lmv2_client_data, lmv2_response);
+        memcpy(final_response.data, lmv2_response, sizeof(lmv2_response));
+
+        /* after the first 16 bytes is the random data we generated above,
+           so the server can verify us with it */
+        memcpy(final_response.data+sizeof(lmv2_response),
+               lmv2_client_data.data, lmv2_client_data.length);
+
+/*        data_blob_free(&lmv2_client_data); */ /* BB fix BB */
+
+        return final_response;
+}
+
+int make_oem_passwd_hash(char data[516], const char *passwd,
 		     unsigned char old_pw_hash[16], int unicode)
 {
 	int new_pw_len = strlen(passwd) * (unicode ? 2 : 1);
@@ -333,32 +381,11 @@
 	DEBUG(100, ("make_oem_passwd_hash\n"));
 	dump_data(100, data, 516);
 #endif
-	SamOEMhash((unsigned char *) data, (unsigned char *) old_pw_hash, TRUE);
+	SamOEMhash((unsigned char *) data, (unsigned char *) old_pw_hash, 516);
 
 	return TRUE;
 }
 
-/* Does the md5 encryption from the NT hash for NTLMv2. */
-void
-SMBOWFencrypt_ntv2(const unsigned char kr[16],
-		   const struct data_blob srv_chal,
-		   const struct data_blob cli_chal, unsigned char resp_buf[16])
-{
-	struct HMACMD5Context ctx;
-
-	hmac_md5_init_limK_to_64(kr, 16, &ctx);
-	hmac_md5_update(srv_chal.data, srv_chal.length, &ctx);
-	hmac_md5_update(cli_chal.data, cli_chal.length, &ctx);
-	hmac_md5_final(resp_buf, &ctx);
-
-#ifdef DEBUG_PASSWORD
-	DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, cli_chal, resp_buf\n"));
-	dump_data(100, srv_chal.data, srv_chal.length);
-	dump_data(100, cli_chal.data, cli_chal.length);
-	dump_data(100, resp_buf, 16);
-#endif
-}
-
 void
 SMBsesskeygen_ntv2(const unsigned char kr[16],
 		   const unsigned char *nt_resp, __u8 sess_key[16])
@@ -407,6 +434,44 @@
 	return TRUE;
 }
 
+int SMBNTLMv2encrypt(const char *user, const char *domain, const char *password,
+                      const struct data_blob *server_chal,
+                      const struct data_blob *names_blob,
+                      struct data_blob *lm_response, struct data_blob *nt_response,
+                      struct data_blob *nt_session_key,struct nls_table * nls_codepage)
+{
+        unsigned char nt_hash[16];
+        unsigned char ntlm_v2_hash[16];
+        E_md4hash(password, nt_hash);
+
+        /* We don't use the NT# directly.  Instead we use it mashed up with
+           the username and domain.
+           This prevents username swapping during the auth exchange
+        */
+        ntv2_owf_gen(nt_hash, user, domain, ntlm_v2_hash,nls_codepage);
+
+        if (nt_response) {
+/*                *nt_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal,
+                                                        names_blob); */ /* BB fix BB */
+                if (nt_session_key) {
+/*                        *nt_session_key = data_blob(NULL, 16); */ /* BB fix BB */
+
+                        /* The NTLMv2 calculations also provide a session key, for signing etc later */
+                        /* use only the first 16 bytes of nt_response for session key */
+                        SMBsesskeygen_ntv2(ntlm_v2_hash, nt_response->data, nt_session_key->data);
+                }
+        }
+
+        /* LMv2 */
+
+        if (lm_response) {
+                *lm_response = LMv2_generate_response(ntlm_v2_hash, server_chal);
+        }
+
+        return TRUE;
+}
+
+
 /***********************************************************
  SMB signing - setup the MAC key.
 ************************************************************/
@@ -455,7 +520,7 @@
 		  be32_to_cpu(outbuf->smb_buf_length));
 	MD5Final(calc_md5_mac, &md5_ctx);
 
-	memcpy(outbuf->SecuritySignature, calc_md5_mac, 8);
+	memcpy(outbuf->Signature.SecuritySignature, calc_md5_mac, 8);
 	(*send_seq_num)++;
 	*reply_seq_num = *send_seq_num;
 	(*send_seq_num)++;
diff -urN linux-2.5.74-bk4/fs/cifs/transport.c linux-2.5.74-bk5/fs/cifs/transport.c
--- linux-2.5.74-bk4/fs/cifs/transport.c	2003-07-02 13:44:00.000000000 -0700
+++ linux-2.5.74-bk5/fs/cifs/transport.c	2003-07-07 04:57:16.000000000 -0700
@@ -154,12 +154,8 @@
 
 	/* smb header is converted in header_assemble. bcc and rest of SMB word
 	   area, and byte area if necessary, is converted to littleendian in 
-	   cifssmb.c and RFC1001 len is converted to bigendian in smb_send */
-	if (smb_buf_length > 12)
-		smb_buffer->Flags2 = cpu_to_le16(smb_buffer->Flags2);
-
-	/* if(smb_buffer->Flags2 & SMBFLG2_SECURITY_SIGNATURE)
-		sign_smb(smb_buffer); */ /* BB enable when signing tested more */
+	   cifssmb.c and RFC1001 len is converted to bigendian in smb_send 
+	   Flags2 is converted in SendReceive */
 
 	smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
 	cFYI(1, ("Sending smb of length %d ", smb_buf_length));
@@ -200,6 +196,12 @@
 		DeleteMidQEntry(midQ);
 		return -EIO;
 	}
+
+        if (in_buf->smb_buf_length > 12)
+                in_buf->Flags2 = cpu_to_le16(in_buf->Flags2);
+
+        rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number);
+
 	midQ->midState = MID_REQUEST_SUBMITTED;
 	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
 		      (struct sockaddr *) &(ses->server->sockAddr));
@@ -247,11 +249,18 @@
 			memcpy(out_buf, midQ->resp_buf,
 			       receive_len +
 			       4 /* include 4 byte RFC1001 header */ );
-			/* convert the length back to a form that we can use */
 
 			dump_smb(out_buf, 92);
+			/* convert the length into a more usable form */
 			out_buf->smb_buf_length =
 			    be32_to_cpu(out_buf->smb_buf_length);
+			if((out_buf->smb_buf_length > 24) &&
+			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) {
+				rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */
+				if(rc)
+					cFYI(1,("Unexpected signature received from server"));
+			}
+
 			if (out_buf->smb_buf_length > 12)
 				out_buf->Flags2 = le16_to_cpu(out_buf->Flags2);
 			if (out_buf->smb_buf_length > 28)
diff -urN linux-2.5.74-bk4/fs/cifs/xattr.c linux-2.5.74-bk5/fs/cifs/xattr.c
--- linux-2.5.74-bk4/fs/cifs/xattr.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.5.74-bk5/fs/cifs/xattr.c	2003-07-07 04:57:16.000000000 -0700
@@ -0,0 +1,56 @@
+/*
+ *   fs/cifs/xattr.c
+ *
+ *   Copyright (c) International Business Machines  Corp., 2003
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/fs.h>
+
+int cifs_removexattr(struct dentry * direntry, const char * name)
+{
+        int rc = -EOPNOTSUPP;
+        return rc;
+}
+
+int cifs_setxattr(struct dentry * direntry, const char * name,
+        const void * value, size_t size, int flags)
+{
+        int rc = -EOPNOTSUPP;
+        return rc;
+}
+
+ssize_t cifs_getxattr(struct dentry * direntry, const char * name,
+         void * value, size_t size)
+{
+        ssize_t rc = -EOPNOTSUPP;
+        return rc;
+}
+
+ssize_t cifs_listxattr(struct dentry * direntry, char * ea_data, size_t ea_size)
+{
+        ssize_t rc = -EOPNOTSUPP;
+
+	/* return dosattributes as pseudo xattr */
+	/* return alt name if available as pseudo attr */
+
+	/* if proc/fs/cifs/streamstoxattr is set then
+		search server for EAs or streams to 
+		returns as xattrs */
+
+        return rc;
+}
diff -urN linux-2.5.74-bk4/fs/dquot.c linux-2.5.74-bk5/fs/dquot.c
--- linux-2.5.74-bk4/fs/dquot.c	2003-07-02 13:50:56.000000000 -0700
+++ linux-2.5.74-bk5/fs/dquot.c	2003-07-07 04:57:16.000000000 -0700
@@ -74,6 +74,7 @@
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/security.h>
+#include <linux/kmod.h>
 
 #include <asm/uaccess.h>
 
@@ -96,6 +97,7 @@
 
 static char *quotatypes[] = INITQFNAMES;
 static struct quota_format_type *quota_formats;	/* List of registered formats */
+static struct quota_module_name module_names[] = INIT_QUOTA_MODULE_NAMES;
 
 int register_quota_format(struct quota_format_type *fmt)
 {
@@ -123,8 +125,19 @@
 
 	spin_lock(&dq_list_lock);
 	for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; actqf = actqf->qf_next);
-	if (actqf && !try_module_get(actqf->qf_owner))
-		actqf = NULL;
+	if (!actqf || !try_module_get(actqf->qf_owner)) {
+		int qm;
+
+		for (qm = 0; module_names[qm].qm_fmt_id && module_names[qm].qm_fmt_id != id; qm++);
+		if (!module_names[qm].qm_fmt_id || request_module(module_names[qm].qm_mod_name)) {
+			actqf = NULL;
+			goto out;
+		}
+		for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; actqf = actqf->qf_next);
+		if (actqf && !try_module_get(actqf->qf_owner))
+			actqf = NULL;
+	}
+out:
 	spin_unlock(&dq_list_lock);
 	return actqf;
 }
diff -urN linux-2.5.74-bk4/fs/ext2/acl.c linux-2.5.74-bk5/fs/ext2/acl.c
--- linux-2.5.74-bk4/fs/ext2/acl.c	2003-07-07 04:56:56.000000000 -0700
+++ linux-2.5.74-bk5/fs/ext2/acl.c	2003-07-07 04:57:16.000000000 -0700
@@ -1,7 +1,7 @@
 /*
  * linux/fs/ext2/acl.c
  *
- * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
+ * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
  */
 
 #include <linux/init.h>
@@ -19,7 +19,7 @@
 ext2_acl_from_disk(const void *value, size_t size)
 {
 	const char *end = (char *)value + size;
-	int n, count;
+	size_t n, count;
 	struct posix_acl *acl;
 
 	if (!value)
@@ -85,7 +85,7 @@
 {
 	ext2_acl_header *ext_acl;
 	char *e;
-	int n;
+	size_t n;
 
 	*size = ext2_acl_size(acl->a_count);
 	ext_acl = (ext2_acl_header *)kmalloc(sizeof(ext2_acl_header) +
@@ -124,16 +124,41 @@
 	return ERR_PTR(-EINVAL);
 }
 
+static inline struct posix_acl *
+ext2_iget_acl(struct inode *inode, struct posix_acl **i_acl)
+{
+	struct posix_acl *acl = EXT2_ACL_NOT_CACHED;
+
+	spin_lock(&inode->i_lock);
+	if (*i_acl != EXT2_ACL_NOT_CACHED)
+		acl = posix_acl_dup(*i_acl);
+	spin_unlock(&inode->i_lock);
+
+	return acl;
+}
+
+static inline void
+ext2_iset_acl(struct inode *inode, struct posix_acl **i_acl,
+		   struct posix_acl *acl)
+{
+	spin_lock(&inode->i_lock);
+	if (*i_acl != EXT2_ACL_NOT_CACHED)
+		posix_acl_release(*i_acl);
+	*i_acl = posix_acl_dup(acl);
+	spin_unlock(&inode->i_lock);
+}
+
 /*
- * inode->i_sem: down
+ * inode->i_sem: don't care
  */
 static struct posix_acl *
 ext2_get_acl(struct inode *inode, int type)
 {
+	const size_t max_size = ext2_acl_size(EXT2_ACL_MAX_ENTRIES);
+	struct ext2_inode_info *ei = EXT2_I(inode);
 	int name_index;
 	char *value;
-	struct posix_acl *acl, **p_acl;
-	const size_t size = ext2_acl_size(EXT2_ACL_MAX_ENTRIES);
+	struct posix_acl *acl;
 	int retval;
 
 	if (!test_opt(inode->i_sb, POSIX_ACL))
@@ -141,36 +166,45 @@
 
 	switch(type) {
 		case ACL_TYPE_ACCESS:
-			p_acl = &EXT2_I(inode)->i_acl;
+			acl = ext2_iget_acl(inode, &ei->i_acl);
+			if (acl != EXT2_ACL_NOT_CACHED)
+				return acl;
 			name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
 			break;
 
 		case ACL_TYPE_DEFAULT:
-			p_acl = &EXT2_I(inode)->i_default_acl;
+			acl = ext2_iget_acl(inode, &ei->i_default_acl);
+			if (acl != EXT2_ACL_NOT_CACHED)
+				return acl;
 			name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT;
 			break;
 
 		default:
 			return ERR_PTR(-EINVAL);
 	}
-	if (*p_acl != EXT2_ACL_NOT_CACHED)
-		return posix_acl_dup(*p_acl);
-	value = kmalloc(size, GFP_KERNEL);
+	value = kmalloc(max_size, GFP_KERNEL);
 	if (!value)
 		return ERR_PTR(-ENOMEM);
 
-	retval = ext2_xattr_get(inode, name_index, "", value, size);
-
-	if (retval == -ENODATA || retval == -ENOSYS)
-		*p_acl = acl = NULL;
-	else if (retval < 0)
-		acl = ERR_PTR(retval);
-	else {
+	retval = ext2_xattr_get(inode, name_index, "", value, max_size);
+	acl = ERR_PTR(retval);
+	if (retval >= 0)
 		acl = ext2_acl_from_disk(value, retval);
-		if (!IS_ERR(acl))
-			*p_acl = posix_acl_dup(acl);
-	}
+	else if (retval == -ENODATA || retval == -ENOSYS)
+		acl = NULL;
 	kfree(value);
+
+	if (!IS_ERR(acl)) {
+		switch(type) {
+			case ACL_TYPE_ACCESS:
+				ext2_iset_acl(inode, &ei->i_acl, acl);
+				break;
+
+			case ACL_TYPE_DEFAULT:
+				ext2_iset_acl(inode, &ei->i_default_acl, acl);
+				break;
+		}
+	}
 	return acl;
 }
 
@@ -180,9 +214,9 @@
 static int
 ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
 {
+	struct ext2_inode_info *ei = EXT2_I(inode);
 	int name_index;
 	void *value = NULL;
-	struct posix_acl **p_acl;
 	size_t size;
 	int error;
 
@@ -194,7 +228,6 @@
 	switch(type) {
 		case ACL_TYPE_ACCESS:
 			name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
-			p_acl = &EXT2_I(inode)->i_acl;
 			if (acl) {
 				mode_t mode = inode->i_mode;
 				error = posix_acl_equiv_mode(acl, &mode);
@@ -211,7 +244,6 @@
 
 		case ACL_TYPE_DEFAULT:
 			name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT;
-			p_acl = &EXT2_I(inode)->i_default_acl;
 			if (!S_ISDIR(inode->i_mode))
 				return acl ? -EACCES : 0;
 			break;
@@ -232,15 +264,26 @@
 	if (value)
 		kfree(value);
 	if (!error) {
-		if (*p_acl && *p_acl != EXT2_ACL_NOT_CACHED)
-			posix_acl_release(*p_acl);
-		*p_acl = posix_acl_dup(acl);
+		switch(type) {
+			case ACL_TYPE_ACCESS:
+				ext2_iset_acl(inode, &ei->i_acl, acl);
+				break;
+
+			case ACL_TYPE_DEFAULT:
+				ext2_iset_acl(inode, &ei->i_default_acl, acl);
+				break;
+		}
 	}
 	return error;
 }
 
-static int
-__ext2_permission(struct inode *inode, int mask, int lock)
+/*
+ * Inode operation permission().
+ *
+ * inode->i_sem: don't care
+ */
+int
+ext2_permission(struct inode *inode, int mask, struct nameidata *nd)
 {
 	int mode = inode->i_mode;
 
@@ -254,29 +297,16 @@
 	if (current->fsuid == inode->i_uid) {
 		mode >>= 6;
 	} else if (test_opt(inode->i_sb, POSIX_ACL)) {
-		/* ACL can't contain additional permissions if
-		   the ACL_MASK entry is 0 */
-		if (!(mode & S_IRWXG))
-			goto check_groups;
-		if (EXT2_I(inode)->i_acl == EXT2_ACL_NOT_CACHED) {
-			struct posix_acl *acl;
-
-			if (lock) {
-				down(&inode->i_sem);
-				acl = ext2_get_acl(inode, ACL_TYPE_ACCESS);
-				up(&inode->i_sem);
-			} else
-				acl = ext2_get_acl(inode, ACL_TYPE_ACCESS);
+		struct posix_acl *acl;
 
-			if (IS_ERR(acl))
-				return PTR_ERR(acl);
+		/* The access ACL cannot grant access if the group class
+		   permission bits don't contain all requested permissions. */
+		if (((mode >> 3) & mask & S_IRWXO) != mask)
+			goto check_groups;
+		acl = ext2_get_acl(inode, ACL_TYPE_ACCESS);
+		if (acl) {
+			int error = posix_acl_permission(inode, acl, mask);
 			posix_acl_release(acl);
-			if (EXT2_I(inode)->i_acl == EXT2_ACL_NOT_CACHED)
-				return -EIO;
-		}
-		if (EXT2_I(inode)->i_acl) {
-			int error = posix_acl_permission(inode,
-				EXT2_I(inode)->i_acl, mask);
 			if (error == -EACCES)
 				goto check_capabilities;
 			return error;
@@ -303,32 +333,10 @@
 }
 
 /*
- * Inode operation permission().
- *
- * inode->i_sem: up
- * BKL held [before 2.5.x]
- */
-int
-ext2_permission(struct inode *inode, int mask, struct nameidata *nd)
-{
-	return __ext2_permission(inode, mask, 1);
-}
-
-/*
- * Used internally if i_sem is already down.
- */
-int
-ext2_permission_locked(struct inode *inode, int mask)
-{
-	return __ext2_permission(inode, mask, 0);
-}
-
-/*
  * Initialize the ACLs of a new inode. Called from ext2_new_inode.
  *
  * dir->i_sem: down
  * inode->i_sem: up (access to inode is still exclusive)
- * BKL held [before 2.5.x] 
  */
 int
 ext2_init_acl(struct inode *inode, struct inode *dir)
@@ -388,7 +396,6 @@
  * file mode.
  *
  * inode->i_sem: down
- * BKL held [before 2.5.x]
  */
 int
 ext2_acl_chmod(struct inode *inode)
diff -urN linux-2.5.74-bk4/fs/ext2/acl.h linux-2.5.74-bk5/fs/ext2/acl.h
--- linux-2.5.74-bk4/fs/ext2/acl.h	2003-07-07 04:56:56.000000000 -0700
+++ linux-2.5.74-bk5/fs/ext2/acl.h	2003-07-07 04:57:16.000000000 -0700
@@ -60,7 +60,6 @@
 
 /* acl.c */
 extern int ext2_permission (struct inode *, int, struct nameidata *);
-extern int ext2_permission_locked (struct inode *, int);
 extern int ext2_acl_chmod (struct inode *);
 extern int ext2_init_acl (struct inode *, struct inode *);
 
diff -urN linux-2.5.74-bk4/fs/ext2/ext2.h linux-2.5.74-bk5/fs/ext2/ext2.h
--- linux-2.5.74-bk4/fs/ext2/ext2.h	2003-07-02 13:57:41.000000000 -0700
+++ linux-2.5.74-bk5/fs/ext2/ext2.h	2003-07-07 04:57:16.000000000 -0700
@@ -41,6 +41,16 @@
 	__u32	i_prealloc_block;
 	__u32	i_prealloc_count;
 	__u32	i_dir_start_lookup;
+#ifdef CONFIG_EXT2_FS_XATTR
+	/*
+	 * Extended attributes can be read independently of the main file
+	 * data. Taking i_sem even when reading would cause contention
+	 * between readers of EAs and writers of regular file data, so
+	 * instead we synchronize on xattr_sem when reading or changing
+	 * EAs.
+	 */
+	struct rw_semaphore xattr_sem;
+#endif
 #ifdef CONFIG_EXT2_FS_POSIX_ACL
 	struct posix_acl	*i_acl;
 	struct posix_acl	*i_default_acl;
diff -urN linux-2.5.74-bk4/fs/ext2/super.c linux-2.5.74-bk5/fs/ext2/super.c
--- linux-2.5.74-bk4/fs/ext2/super.c	2003-07-02 13:50:20.000000000 -0700
+++ linux-2.5.74-bk5/fs/ext2/super.c	2003-07-07 04:57:16.000000000 -0700
@@ -177,6 +177,9 @@
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR) {
 		rwlock_init(&ei->i_meta_lock);
+#ifdef CONFIG_EXT2_FS_XATTR
+		init_rwsem(&ei->xattr_sem);
+#endif
 		inode_init_once(&ei->vfs_inode);
 	}
 }
diff -urN linux-2.5.74-bk4/fs/ext2/xattr.c linux-2.5.74-bk5/fs/ext2/xattr.c
--- linux-2.5.74-bk4/fs/ext2/xattr.c	2003-07-02 13:50:05.000000000 -0700
+++ linux-2.5.74-bk5/fs/ext2/xattr.c	2003-07-07 04:57:16.000000000 -0700
@@ -1,7 +1,7 @@
 /*
  * linux/fs/ext2/xattr.c
  *
- * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
+ * Copyright (C) 2001-2003 Andreas Gruenbacher <agruen@suse.de>
  *
  * Fix by Harrison Xing <harrison@mountainviewdata.com>.
  * Extended attributes for symlinks and special files added per
@@ -42,13 +42,12 @@
  *
  * Locking strategy
  * ----------------
- * The VFS already holds the BKL and the inode->i_sem semaphore when any of
- * the xattr inode operations are called, so we are guaranteed that only one
- * processes accesses extended attributes of an inode at any time.
- *
- * For writing we also grab the ext2_xattr_sem semaphore. This ensures that
- * only a single process is modifying an extended attribute block, even
- * if the block is shared among inodes.
+ * EXT2_I(inode)->i_file_acl is protected by EXT2_I(inode)->xattr_sem.
+ * EA blocks are only changed if they are exclusive to an inode, so
+ * holding xattr_sem also means that nothing but the EA block's reference
+ * count will change. Multiple writers to an EA block are synchronized
+ * by the bh lock. No more than a single bh lock is held at any time
+ * to avoid deadlocks.
  */
 
 #include <linux/buffer_head.h>
@@ -57,7 +56,7 @@
 #include <linux/slab.h>
 #include <linux/mbcache.h>
 #include <linux/quotaops.h>
-#include <asm/semaphore.h>
+#include <linux/rwsem.h>
 #include "ext2.h"
 #include "xattr.h"
 #include "acl.h"
@@ -83,8 +82,9 @@
 	} while (0)
 # define ea_bdebug(bh, f...) do { \
 		char b[BDEVNAME_SIZE]; \
-		printk(KERN_DEBUG "block %s:%ld: ", \
-			bdevname(bh->b_bdev, b), bh->b_blocknr); \
+		printk(KERN_DEBUG "block %s:%lu: ", \
+			bdevname(bh->b_bdev, b), \
+			(unsigned long) bh->b_blocknr); \
 		printk(f); \
 		printk("\n"); \
 	} while (0)
@@ -104,15 +104,6 @@
 			      struct ext2_xattr_entry *);
 
 static struct mb_cache *ext2_xattr_cache;
-
-/*
- * If a file system does not share extended attributes among inodes,
- * we should not need the ext2_xattr_sem semaphore. However, the
- * filesystem may still contain shared blocks, so we always take
- * the lock.
- */
-
-static DECLARE_MUTEX(ext2_xattr_sem);
 static struct ext2_xattr_handler *ext2_xattr_handlers[EXT2_XATTR_INDEX_MAX];
 static rwlock_t ext2_handler_lock = RW_LOCK_UNLOCKED;
 
@@ -195,8 +186,7 @@
 /*
  * Inode operation getxattr()
  *
- * dentry->d_inode->i_sem down
- * BKL held [before 2.5.x]
+ * dentry->d_inode->i_sem: don't care
  */
 ssize_t
 ext2_getxattr(struct dentry *dentry, const char *name,
@@ -214,8 +204,7 @@
 /*
  * Inode operation listxattr()
  *
- * dentry->d_inode->i_sem down
- * BKL held [before 2.5.x]
+ * dentry->d_inode->i_sem: don't care
  */
 ssize_t
 ext2_listxattr(struct dentry *dentry, char *buffer, size_t size)
@@ -226,8 +215,7 @@
 /*
  * Inode operation setxattr()
  *
- * dentry->d_inode->i_sem down
- * BKL held [before 2.5.x]
+ * dentry->d_inode->i_sem: down
  */
 int
 ext2_setxattr(struct dentry *dentry, const char *name,
@@ -247,8 +235,7 @@
 /*
  * Inode operation removexattr()
  *
- * dentry->d_inode->i_sem down
- * BKL held [before 2.5.x]
+ * dentry->d_inode->i_sem: down
  */
 int
 ext2_removexattr(struct dentry *dentry, const char *name)
@@ -278,21 +265,24 @@
 {
 	struct buffer_head *bh = NULL;
 	struct ext2_xattr_entry *entry;
-	unsigned int size;
+	size_t name_len, size;
 	char *end;
-	int name_len, error;
+	int error;
 
 	ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
 		  name_index, name, buffer, (long)buffer_size);
 
 	if (name == NULL)
 		return -EINVAL;
+	down_read(&EXT2_I(inode)->xattr_sem);
+	error = -ENODATA;
 	if (!EXT2_I(inode)->i_file_acl)
-		return -ENODATA;
+		goto cleanup;
 	ea_idebug(inode, "reading block %d", EXT2_I(inode)->i_file_acl);
 	bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl);
+	error = -EIO;
 	if (!bh)
-		return -EIO;
+		goto cleanup;
 	ea_bdebug(bh, "b_count=%d, refcount=%d",
 		atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
 	end = bh->b_data + bh->b_size;
@@ -357,6 +347,7 @@
 
 cleanup:
 	brelse(bh);
+	up_read(&EXT2_I(inode)->xattr_sem);
 
 	return error;
 }
@@ -376,19 +367,22 @@
 {
 	struct buffer_head *bh = NULL;
 	struct ext2_xattr_entry *entry;
-	unsigned int size = 0;
+	size_t size = 0;
 	char *buf, *end;
 	int error;
 
 	ea_idebug(inode, "buffer=%p, buffer_size=%ld",
 		  buffer, (long)buffer_size);
 
+	down_read(&EXT2_I(inode)->xattr_sem);
+	error = 0;
 	if (!EXT2_I(inode)->i_file_acl)
-		return 0;
+		goto cleanup;
 	ea_idebug(inode, "reading block %d", EXT2_I(inode)->i_file_acl);
 	bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl);
+	error = -EIO;
 	if (!bh)
-		return -EIO;
+		goto cleanup;
 	ea_bdebug(bh, "b_count=%d, refcount=%d",
 		atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
 	end = bh->b_data + bh->b_size;
@@ -441,6 +435,7 @@
 
 cleanup:
 	brelse(bh);
+	up_read(&EXT2_I(inode)->xattr_sem);
 
 	return error;
 }
@@ -482,8 +477,8 @@
 	struct buffer_head *bh = NULL;
 	struct ext2_xattr_header *header = NULL;
 	struct ext2_xattr_entry *here, *last;
-	unsigned int name_len;
-	int min_offs = sb->s_blocksize, not_found = 1, free, error;
+	size_t name_len, free, min_offs = sb->s_blocksize;
+	int not_found = 1, error;
 	char *end;
 	
 	/*
@@ -512,8 +507,7 @@
 	name_len = strlen(name);
 	if (name_len > 255 || value_len > sb->s_blocksize)
 		return -ERANGE;
-	down(&ext2_xattr_sem);
-
+	down_write(&EXT2_I(inode)->xattr_sem);
 	if (EXT2_I(inode)->i_file_acl) {
 		/* The inode already has an extended attribute block. */
 		bh = sb_bread(sb, EXT2_I(inode)->i_file_acl);
@@ -540,7 +534,7 @@
 			if ((char *)next >= end)
 				goto bad_block;
 			if (!here->e_value_block && here->e_value_size) {
-				int offs = le16_to_cpu(here->e_value_offs);
+				size_t offs = le16_to_cpu(here->e_value_offs);
 				if (offs < min_offs)
 					min_offs = offs;
 			}
@@ -560,7 +554,7 @@
 			if ((char *)next >= end)
 				goto bad_block;
 			if (!last->e_value_block && last->e_value_size) {
-				int offs = le16_to_cpu(last->e_value_offs);
+				size_t offs = le16_to_cpu(last->e_value_offs);
 				if (offs < min_offs)
 					min_offs = offs;
 			}
@@ -584,36 +578,38 @@
 		error = 0;
 		if (value == NULL)
 			goto cleanup;
-		else
-			free -= EXT2_XATTR_LEN(name_len);
 	} else {
 		/* Request to create an existing attribute? */
 		error = -EEXIST;
 		if (flags & XATTR_CREATE)
 			goto cleanup;
 		if (!here->e_value_block && here->e_value_size) {
-			unsigned int size = le32_to_cpu(here->e_value_size);
+			size_t size = le32_to_cpu(here->e_value_size);
 
 			if (le16_to_cpu(here->e_value_offs) + size > 
 			    sb->s_blocksize || size > sb->s_blocksize)
 				goto bad_block;
 			free += EXT2_XATTR_SIZE(size);
 		}
+		free += EXT2_XATTR_LEN(name_len);
 	}
-	free -= EXT2_XATTR_SIZE(value_len);
 	error = -ENOSPC;
-	if (free < 0)
+	if (free < EXT2_XATTR_LEN(name_len) + EXT2_XATTR_SIZE(value_len))
 		goto cleanup;
 
 	/* Here we know that we can set the new attribute. */
 
 	if (header) {
+		/* assert(header == HDR(bh)); */
+		lock_buffer(bh);
 		if (header->h_refcount == cpu_to_le32(1)) {
 			ea_bdebug(bh, "modifying in-place");
 			ext2_xattr_cache_remove(bh);
+			/* keep the buffer locked while modifying it. */
 		} else {
 			int offset;
 
+			unlock_buffer(bh);
 			ea_bdebug(bh, "cloning");
 			header = kmalloc(bh->b_size, GFP_KERNEL);
 			error = -ENOMEM;
@@ -638,23 +634,36 @@
 		last = here = ENTRY(header+1);
 	}
 
+	/* Iff we are modifying the block in-place, bh is locked here. */
+
 	if (not_found) {
 		/* Insert the new name. */
-		int size = EXT2_XATTR_LEN(name_len);
-		int rest = (char *)last - (char *)here;
+		size_t size = EXT2_XATTR_LEN(name_len);
+		size_t rest = (char *)last - (char *)here;
 		memmove((char *)here + size, here, rest);
 		memset(here, 0, size);
 		here->e_name_index = name_index;
 		here->e_name_len = name_len;
 		memcpy(here->e_name, name, name_len);
 	} else {
-		/* Remove the old value. */
 		if (!here->e_value_block && here->e_value_size) {
 			char *first_val = (char *)header + min_offs;
-			int offs = le16_to_cpu(here->e_value_offs);
+			size_t offs = le16_to_cpu(here->e_value_offs);
 			char *val = (char *)header + offs;
 			size_t size = EXT2_XATTR_SIZE(
 				le32_to_cpu(here->e_value_size));
+
+			if (size == EXT2_XATTR_SIZE(value_len)) {
+				/* The old and the new value have the same
+				   size. Just replace. */
+				here->e_value_size = cpu_to_le32(value_len);
+				memset(val + size - EXT2_XATTR_PAD, 0,
+				       EXT2_XATTR_PAD); /* Clear pad bytes. */
+				memcpy(val, value, value_len);
+				goto skip_replace;
+			}
+
+			/* Remove the old value. */
 			memmove(first_val + size, first_val, val - first_val);
 			memset(first_val, 0, size);
 			here->e_value_offs = 0;
@@ -663,7 +672,7 @@
 			/* Adjust all value offsets. */
 			last = ENTRY(header+1);
 			while (!IS_LAST_ENTRY(last)) {
-				int o = le16_to_cpu(last->e_value_offs);
+				size_t o = le16_to_cpu(last->e_value_offs);
 				if (!last->e_value_block && o < offs)
 					last->e_value_offs =
 						cpu_to_le16(o + size);
@@ -671,19 +680,12 @@
 			}
 		}
 		if (value == NULL) {
-			/* Remove this attribute. */
-			if (EXT2_XATTR_NEXT(ENTRY(header+1)) == last) {
-				/* This block is now empty. */
-				error = ext2_xattr_set2(inode, bh, NULL);
-				goto cleanup;
-			} else {
-				/* Remove the old name. */
-				int size = EXT2_XATTR_LEN(name_len);
-				last = ENTRY((char *)last - size);
-				memmove(here, (char*)here + size,
-					(char*)last - (char*)here);
-				memset(last, 0, size);
-			}
+			/* Remove the old name. */
+			size_t size = EXT2_XATTR_LEN(name_len);
+			last = ENTRY((char *)last - size);
+			memmove(here, (char*)here + size,
+				(char*)last - (char*)here);
+			memset(last, 0, size);
 		}
 	}
 
@@ -700,15 +702,25 @@
 			memcpy(val, value, value_len);
 		}
 	}
-	ext2_xattr_rehash(header, here);
 
-	error = ext2_xattr_set2(inode, bh, header);
+skip_replace:
+	if (IS_LAST_ENTRY(ENTRY(header+1))) {
+		/* This block is now empty. */
+		if (bh && header == HDR(bh))
+			unlock_buffer(bh);  /* we were modifying in-place. */
+		error = ext2_xattr_set2(inode, bh, NULL);
+	} else {
+		ext2_xattr_rehash(header, here);
+		if (bh && header == HDR(bh))
+			unlock_buffer(bh);  /* we were modifying in-place. */
+		error = ext2_xattr_set2(inode, bh, header);
+	}
 
 cleanup:
 	brelse(bh);
 	if (!(bh && header == HDR(bh)))
 		kfree(header);
-	up(&ext2_xattr_sem);
+	up_write(&EXT2_I(inode)->xattr_sem);
 
 	return error;
 }
@@ -728,31 +740,37 @@
 		new_bh = ext2_xattr_cache_find(inode, header);
 		if (new_bh) {
 			/*
-			 * We found an identical block in the cache.
-			 * The old block will be released after updating
-			 * the inode.
+			 * We found an identical block in the cache. The
+			 * block returned is locked. The old block will
+			 * be released after updating the inode.
 			 */
-			ea_bdebug(new_bh, "%s block %ld",
+			ea_bdebug(new_bh, "%s block %lu",
 				(old_bh == new_bh) ? "keeping" : "reusing",
-				new_bh->b_blocknr);
+				(unsigned long) new_bh->b_blocknr);
 			
 			error = -EDQUOT;
-			if (DQUOT_ALLOC_BLOCK(inode, 1))
+			if (DQUOT_ALLOC_BLOCK(inode, 1)) {
+				unlock_buffer(new_bh);
 				goto cleanup;
+			}
 			
 			HDR(new_bh)->h_refcount = cpu_to_le32(
 				le32_to_cpu(HDR(new_bh)->h_refcount) + 1);
 			ea_bdebug(new_bh, "refcount now=%d",
 				le32_to_cpu(HDR(new_bh)->h_refcount));
+			unlock_buffer(new_bh);
 		} else if (old_bh && header == HDR(old_bh)) {
-			/* Keep this block. */
+			/* Keep this block. No need to lock the block as we
+			   don't need to change the reference count. */
 			new_bh = old_bh;
 			get_bh(new_bh);
 			ext2_xattr_cache_insert(new_bh);
 		} else {
 			/* We need to allocate a new block */
-			int goal = le32_to_cpu(EXT2_SB(sb)->s_es->s_first_data_block) +
-				EXT2_I(inode)->i_block_group * EXT2_BLOCKS_PER_GROUP(sb);
+			int goal = le32_to_cpu(EXT2_SB(sb)->s_es->
+						           s_first_data_block) +
+				   EXT2_I(inode)->i_block_group *
+				   EXT2_BLOCKS_PER_GROUP(sb);
 			int block = ext2_new_block(inode, goal, 0, 0, &error);
 			if (error)
 				goto cleanup;
@@ -794,12 +812,11 @@
 	error = 0;
 	if (old_bh && old_bh != new_bh) {
 		/*
-		 * If there was an old block, and we are not still using it,
-		 * we now release the old block.
-		*/
-		unsigned int refcount = le32_to_cpu(HDR(old_bh)->h_refcount);
-
-		if (refcount == 1) {
+		 * If there was an old block and we are no longer using it,
+		 * release the old block.
+		 */
+		lock_buffer(old_bh);
+		if (HDR(old_bh)->h_refcount == cpu_to_le32(1)) {
 			/* Free the old block. */
 			ea_bdebug(old_bh, "freeing");
 			ext2_free_blocks(inode, old_bh->b_blocknr, 1);
@@ -809,12 +826,14 @@
 			bforget(old_bh);
 		} else {
 			/* Decrement the refcount only. */
-			refcount--;
-			HDR(old_bh)->h_refcount = cpu_to_le32(refcount);
+			HDR(old_bh)->h_refcount = cpu_to_le32(
+				le32_to_cpu(HDR(old_bh)->h_refcount) - 1);
 			DQUOT_FREE_BLOCK(inode, 1);
 			mark_buffer_dirty(old_bh);
-			ea_bdebug(old_bh, "refcount now=%d", refcount);
+			ea_bdebug(old_bh, "refcount now=%d",
+				le32_to_cpu(HDR(old_bh)->h_refcount));
 		}
+		unlock_buffer(old_bh);
 	}
 
 cleanup:
@@ -832,12 +851,11 @@
 void
 ext2_xattr_delete_inode(struct inode *inode)
 {
-	struct buffer_head *bh;
+	struct buffer_head *bh = NULL;
 
+	down_write(&EXT2_I(inode)->xattr_sem);
 	if (!EXT2_I(inode)->i_file_acl)
-		return;
-	down(&ext2_xattr_sem);
-
+		goto cleanup;
 	bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl);
 	if (!bh) {
 		ext2_error(inode->i_sb, "ext2_xattr_delete_inode",
@@ -853,12 +871,12 @@
 			EXT2_I(inode)->i_file_acl);
 		goto cleanup;
 	}
-	ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1);
+	lock_buffer(bh);
 	if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
 		ext2_xattr_cache_remove(bh);
 		ext2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1);
+		get_bh(bh);
 		bforget(bh);
-		bh = NULL;
 	} else {
 		HDR(bh)->h_refcount = cpu_to_le32(
 			le32_to_cpu(HDR(bh)->h_refcount) - 1);
@@ -867,11 +885,13 @@
 			sync_dirty_buffer(bh);
 		DQUOT_FREE_BLOCK(inode, 1);
 	}
+	ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1);
+	unlock_buffer(bh);
 	EXT2_I(inode)->i_file_acl = 0;
 
 cleanup:
 	brelse(bh);
-	up(&ext2_xattr_sem);
+	up_write(&EXT2_I(inode)->xattr_sem);
 }
 
 /*
@@ -964,8 +984,8 @@
  *
  * Find an identical extended attribute block.
  *
- * Returns a pointer to the block found, or NULL if such a block was
- * not found or an error occurred.
+ * Returns a locked buffer head to the block found, or NULL if such
+ * a block was not found or an error occurred.
  */
 static struct buffer_head *
 ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header)
@@ -976,7 +996,8 @@
 	if (!header->h_hash)
 		return NULL;  /* never share */
 	ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
-	ce = mb_cache_entry_find_first(ext2_xattr_cache, 0, inode->i_bdev, hash);
+	ce = mb_cache_entry_find_first(ext2_xattr_cache, 0,
+				       inode->i_sb->s_bdev, hash);
 	while (ce) {
 		struct buffer_head *bh = sb_bread(inode->i_sb, ce->e_block);
 
@@ -984,19 +1005,24 @@
 			ext2_error(inode->i_sb, "ext2_xattr_cache_find",
 				"inode %ld: block %ld read error",
 				inode->i_ino, (unsigned long) ce->e_block);
-		} else if (le32_to_cpu(HDR(bh)->h_refcount) >
-			   EXT2_XATTR_REFCOUNT_MAX) {
-			ea_idebug(inode, "block %ld refcount %d>%d",
-				  (unsigned long) ce->e_block,
-				  le32_to_cpu(HDR(bh)->h_refcount),
-				  EXT2_XATTR_REFCOUNT_MAX);
-		} else if (!ext2_xattr_cmp(header, HDR(bh))) {
-			ea_bdebug(bh, "b_count=%d",atomic_read(&(bh->b_count)));
-			mb_cache_entry_release(ce);
-			return bh;
+		} else {
+			lock_buffer(bh);
+			if (le32_to_cpu(HDR(bh)->h_refcount) >
+				   EXT2_XATTR_REFCOUNT_MAX) {
+				ea_idebug(inode, "block %ld refcount %d>%d",
+					  (unsigned long) ce->e_block,
+					  le32_to_cpu(HDR(bh)->h_refcount),
+					  EXT2_XATTR_REFCOUNT_MAX);
+			} else if (!ext2_xattr_cmp(header, HDR(bh))) {
+				ea_bdebug(bh, "b_count=%d",
+					  atomic_read(&(bh->b_count)));
+				mb_cache_entry_release(ce);
+				return bh;
+			}
+			unlock_buffer(bh);
+			brelse(bh);
 		}
-		brelse(bh);
-		ce = mb_cache_entry_find_next(ce, 0, inode->i_bdev, hash);
+		ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash);
 	}
 	return NULL;
 }
diff -urN linux-2.5.74-bk4/fs/ext2/xattr_user.c linux-2.5.74-bk5/fs/ext2/xattr_user.c
--- linux-2.5.74-bk4/fs/ext2/xattr_user.c	2003-07-07 04:56:56.000000000 -0700
+++ linux-2.5.74-bk5/fs/ext2/xattr_user.c	2003-07-07 04:57:16.000000000 -0700
@@ -11,10 +11,6 @@
 #include "ext2.h"
 #include "xattr.h"
 
-#ifdef CONFIG_EXT2_FS_POSIX_ACL
-# include "acl.h"
-#endif
-
 #define XATTR_USER_PREFIX "user."
 
 static size_t
@@ -44,11 +40,7 @@
 		return -EINVAL;
 	if (!test_opt(inode->i_sb, XATTR_USER))
 		return -EOPNOTSUPP;
-#ifdef CONFIG_EXT2_FS_POSIX_ACL
-	error = ext2_permission_locked(inode, MAY_READ);
-#else
 	error = permission(inode, MAY_READ, NULL);
-#endif
 	if (error)
 		return error;
 
@@ -68,11 +60,7 @@
 	if ( !S_ISREG(inode->i_mode) &&
 	    (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
 		return -EPERM;
-#ifdef CONFIG_EXT2_FS_POSIX_ACL
-	error = ext2_permission_locked(inode, MAY_WRITE);
-#else
 	error = permission(inode, MAY_WRITE, NULL);
-#endif
 	if (error)
 		return error;
 
diff -urN linux-2.5.74-bk4/fs/ext3/acl.c linux-2.5.74-bk5/fs/ext3/acl.c
--- linux-2.5.74-bk4/fs/ext3/acl.c	2003-07-07 04:56:56.000000000 -0700
+++ linux-2.5.74-bk5/fs/ext3/acl.c	2003-07-07 04:57:16.000000000 -0700
@@ -1,7 +1,7 @@
 /*
  * linux/fs/ext3/acl.c
  *
- * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
+ * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
  */
 
 #include <linux/init.h>
@@ -20,7 +20,7 @@
 ext3_acl_from_disk(const void *value, size_t size)
 {
 	const char *end = (char *)value + size;
-	int n, count;
+	size_t n, count;
 	struct posix_acl *acl;
 
 	if (!value)
@@ -86,7 +86,7 @@
 {
 	ext3_acl_header *ext_acl;
 	char *e;
-	int n;
+	size_t n;
 
 	*size = ext3_acl_size(acl->a_count);
 	ext_acl = (ext3_acl_header *)kmalloc(sizeof(ext3_acl_header) +
@@ -125,18 +125,43 @@
 	return ERR_PTR(-EINVAL);
 }
 
+static inline struct posix_acl *
+ext3_iget_acl(struct inode *inode, struct posix_acl **i_acl)
+{
+	struct posix_acl *acl = EXT3_ACL_NOT_CACHED;
+
+	spin_lock(&inode->i_lock);
+	if (*i_acl != EXT3_ACL_NOT_CACHED)
+		acl = posix_acl_dup(*i_acl);
+	spin_unlock(&inode->i_lock);
+
+	return acl;
+}
+
+static inline void
+ext3_iset_acl(struct inode *inode, struct posix_acl **i_acl,
+                  struct posix_acl *acl)
+{
+	spin_lock(&inode->i_lock);
+	if (*i_acl != EXT3_ACL_NOT_CACHED)
+		posix_acl_release(*i_acl);
+	*i_acl = posix_acl_dup(acl);
+	spin_unlock(&inode->i_lock);
+}
+
 /*
  * Inode operation get_posix_acl().
  *
- * inode->i_sem: down
+ * inode->i_sem: don't care
  */
 static struct posix_acl *
 ext3_get_acl(struct inode *inode, int type)
 {
+	const size_t max_size = ext3_acl_size(EXT3_ACL_MAX_ENTRIES);
+	struct ext3_inode_info *ei = EXT3_I(inode);
 	int name_index;
 	char *value;
-	struct posix_acl *acl, **p_acl;
-	const size_t size = ext3_acl_size(EXT3_ACL_MAX_ENTRIES);
+	struct posix_acl *acl;
 	int retval;
 
 	if (!test_opt(inode->i_sb, POSIX_ACL))
@@ -144,36 +169,45 @@
 
 	switch(type) {
 		case ACL_TYPE_ACCESS:
-			p_acl = &EXT3_I(inode)->i_acl;
+			acl = ext3_iget_acl(inode, &ei->i_acl);
+			if (acl != EXT3_ACL_NOT_CACHED)
+				return acl;
 			name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
 			break;
 
 		case ACL_TYPE_DEFAULT:
-			p_acl = &EXT3_I(inode)->i_default_acl;
+			acl = ext3_iget_acl(inode, &ei->i_default_acl);
+			if (acl != EXT3_ACL_NOT_CACHED)
+				return acl;
 			name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT;
 			break;
 
 		default:
 			return ERR_PTR(-EINVAL);
 	}
-	if (*p_acl != EXT3_ACL_NOT_CACHED)
-		return posix_acl_dup(*p_acl);
-	value = kmalloc(size, GFP_KERNEL);
+	value = kmalloc(max_size, GFP_KERNEL);
 	if (!value)
 		return ERR_PTR(-ENOMEM);
 
-	retval = ext3_xattr_get(inode, name_index, "", value, size);
-
-	if (retval == -ENODATA || retval == -ENOSYS)
-		*p_acl = acl = NULL;
-	else if (retval < 0)
-		acl = ERR_PTR(retval);
-	else {
+	retval = ext3_xattr_get(inode, name_index, "", value, max_size);
+	acl = ERR_PTR(retval);
+	if (retval > 0)
 		acl = ext3_acl_from_disk(value, retval);
-		if (!IS_ERR(acl))
-			*p_acl = posix_acl_dup(acl);
-	}
+	else if (retval == -ENODATA || retval == -ENOSYS)
+		acl = NULL;
 	kfree(value);
+
+	if (!IS_ERR(acl)) {
+		switch(type) {
+			case ACL_TYPE_ACCESS:
+				ext3_iset_acl(inode, &ei->i_acl, acl);
+				break;
+
+			case ACL_TYPE_DEFAULT:
+				ext3_iset_acl(inode, &ei->i_default_acl, acl);
+				break;
+		}
+	}
 	return acl;
 }
 
@@ -186,9 +220,9 @@
 ext3_set_acl(handle_t *handle, struct inode *inode, int type,
 	     struct posix_acl *acl)
 {
+	struct ext3_inode_info *ei = EXT3_I(inode);
 	int name_index;
 	void *value = NULL;
-	struct posix_acl **p_acl;
 	size_t size;
 	int error;
 
@@ -198,7 +232,6 @@
 	switch(type) {
 		case ACL_TYPE_ACCESS:
 			name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
-			p_acl = &EXT3_I(inode)->i_acl;
 			if (acl) {
 				mode_t mode = inode->i_mode;
 				error = posix_acl_equiv_mode(acl, &mode);
@@ -215,7 +248,6 @@
 
 		case ACL_TYPE_DEFAULT:
 			name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT;
-			p_acl = &EXT3_I(inode)->i_default_acl;
 			if (!S_ISDIR(inode->i_mode))
 				return acl ? -EACCES : 0;
 			break;
@@ -231,20 +263,32 @@
 			return (int)PTR_ERR(value);
 	}
 
-	error = ext3_xattr_set_handle(handle, inode, name_index, "", value, size, 0);
+	error = ext3_xattr_set_handle(handle, inode, name_index, "",
+				      value, size, 0);
 
 	if (value)
 		kfree(value);
 	if (!error) {
-		if (*p_acl && *p_acl != EXT3_ACL_NOT_CACHED)
-			posix_acl_release(*p_acl);
-		*p_acl = posix_acl_dup(acl);
+		switch(type) {
+			case ACL_TYPE_ACCESS:
+				ext3_iset_acl(inode, &ei->i_acl, acl);
+				break;
+
+			case ACL_TYPE_DEFAULT:
+				ext3_iset_acl(inode, &ei->i_default_acl, acl);
+				break;
+		}
 	}
 	return error;
 }
 
-static int
-__ext3_permission(struct inode *inode, int mask, int lock)
+/*
+ * Inode operation permission().
+ *
+ * inode->i_sem: don't care
+ */
+int
+ext3_permission(struct inode *inode, int mask, struct nameidata *nd)
 {
 	int mode = inode->i_mode;
 
@@ -258,29 +302,16 @@
 	if (current->fsuid == inode->i_uid) {
 		mode >>= 6;
 	} else if (test_opt(inode->i_sb, POSIX_ACL)) {
-		/* ACL can't contain additional permissions if
-		   the ACL_MASK entry is 0 */
-		if (!(mode & S_IRWXG))
-			goto check_groups;
-		if (EXT3_I(inode)->i_acl == EXT3_ACL_NOT_CACHED) {
-			struct posix_acl *acl;
-
-			if (lock) {
-				down(&inode->i_sem);
-				acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
-				up(&inode->i_sem);
-			} else
-				acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
+		struct posix_acl *acl;
 
-			if (IS_ERR(acl))
-				return PTR_ERR(acl);
+		/* The access ACL cannot grant access if the group class
+		   permission bits don't contain all requested permissions. */
+		if (((mode >> 3) & mask & S_IRWXO) != mask)
+			goto check_groups;
+		acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
+		if (acl) {
+			int error = posix_acl_permission(inode, acl, mask);
 			posix_acl_release(acl);
-			if (EXT3_I(inode)->i_acl == EXT3_ACL_NOT_CACHED)
-				return -EIO;
-		}
-		if (EXT3_I(inode)->i_acl) {
-			int error = posix_acl_permission(inode,
-				EXT3_I(inode)->i_acl, mask);
 			if (error == -EACCES)
 				goto check_capabilities;
 			return error;
@@ -307,26 +338,6 @@
 }
 
 /*
- * Inode operation permission().
- *
- * inode->i_sem: up
- */
-int
-ext3_permission(struct inode *inode, int mask, struct nameidata *nd)
-{
-	return __ext3_permission(inode, mask, 1);
-}
-
-/*
- * Used internally if i_sem is already down.
- */
-int
-ext3_permission_locked(struct inode *inode, int mask)
-{
-	return __ext3_permission(inode, mask, 0);
-}
-
-/*
  * Initialize the ACLs of a new inode. Called from ext3_new_inode.
  *
  * dir->i_sem: down
diff -urN linux-2.5.74-bk4/fs/ext3/acl.h linux-2.5.74-bk5/fs/ext3/acl.h
--- linux-2.5.74-bk4/fs/ext3/acl.h	2003-07-07 04:56:56.000000000 -0700
+++ linux-2.5.74-bk5/fs/ext3/acl.h	2003-07-07 04:57:16.000000000 -0700
@@ -60,7 +60,6 @@
 
 /* acl.c */
 extern int ext3_permission (struct inode *, int, struct nameidata *);
-extern int ext3_permission_locked (struct inode *, int);
 extern int ext3_acl_chmod (struct inode *);
 extern int ext3_init_acl (handle_t *, struct inode *, struct inode *);
 
diff -urN linux-2.5.74-bk4/fs/ext3/super.c linux-2.5.74-bk5/fs/ext3/super.c
--- linux-2.5.74-bk4/fs/ext3/super.c	2003-07-02 13:55:48.000000000 -0700
+++ linux-2.5.74-bk5/fs/ext3/super.c	2003-07-07 04:57:16.000000000 -0700
@@ -519,6 +519,9 @@
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR) {
 		INIT_LIST_HEAD(&ei->i_orphan);
+#ifdef CONFIG_EXT3_FS_XATTR
+		init_rwsem(&ei->xattr_sem);
+#endif
 		init_rwsem(&ei->truncate_sem);
 		inode_init_once(&ei->vfs_inode);
 	}
diff -urN linux-2.5.74-bk4/fs/ext3/xattr.c linux-2.5.74-bk5/fs/ext3/xattr.c
--- linux-2.5.74-bk4/fs/ext3/xattr.c	2003-07-02 13:49:13.000000000 -0700
+++ linux-2.5.74-bk5/fs/ext3/xattr.c	2003-07-07 04:57:17.000000000 -0700
@@ -1,7 +1,7 @@
 /*
  * linux/fs/ext3/xattr.c
  *
- * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
+ * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
  *
  * Fix by Harrison Xing <harrison@mountainviewdata.com>.
  * Ext3 code with a lot of help from Eric Jarman <ejarman@acm.org>.
@@ -43,13 +43,12 @@
  *
  * Locking strategy
  * ----------------
- * The VFS holdsinode->i_sem semaphore when any of the xattr inode
- * operations are called, so we are guaranteed that only one
- * processes accesses extended attributes of an inode at any time.
- *
- * For writing we also grab the ext3_xattr_sem semaphore. This ensures that
- * only a single process is modifying an extended attribute block, even
- * if the block is shared among inodes.
+ * EXT3_I(inode)->i_file_acl is protected by EXT3_I(inode)->xattr_sem.
+ * EA blocks are only changed if they are exclusive to an inode, so
+ * holding xattr_sem also means that nothing but the EA block's reference
+ * count will change. Multiple writers to an EA block are synchronized
+ * by the bh lock. No more than a single bh lock is held at any time
+ * to avoid deadlocks.
  */
 
 #include <linux/init.h>
@@ -59,12 +58,10 @@
 #include <linux/ext3_fs.h>
 #include <linux/mbcache.h>
 #include <linux/quotaops.h>
-#include <asm/semaphore.h>
+#include <linux/rwsem.h>
 #include "xattr.h"
 #include "acl.h"
 
-#define EXT3_EA_USER "user."
-
 #define HDR(bh) ((struct ext3_xattr_header *)((bh)->b_data))
 #define ENTRY(ptr) ((struct ext3_xattr_entry *)(ptr))
 #define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1)
@@ -79,8 +76,9 @@
 	} while (0)
 # define ea_bdebug(bh, f...) do { \
 		char b[BDEVNAME_SIZE]; \
-		printk(KERN_DEBUG "block %s:%ld: ", \
-			bdevname(bh->b_bdev, b), bh->b_blocknr); \
+		printk(KERN_DEBUG "block %s:%lu: ", \
+			bdevname(bh->b_bdev, b), \
+			(unsigned long) bh->b_blocknr); \
 		printk(f); \
 		printk("\n"); \
 	} while (0)
@@ -94,22 +92,14 @@
 				  struct ext3_xattr_header *);
 
 static int ext3_xattr_cache_insert(struct buffer_head *);
-static struct buffer_head *ext3_xattr_cache_find(struct inode *,
-						 struct ext3_xattr_header *);
+static struct buffer_head *ext3_xattr_cache_find(handle_t *, struct inode *,
+						 struct ext3_xattr_header *,
+						 int *);
 static void ext3_xattr_cache_remove(struct buffer_head *);
 static void ext3_xattr_rehash(struct ext3_xattr_header *,
 			      struct ext3_xattr_entry *);
 
 static struct mb_cache *ext3_xattr_cache;
-
-/*
- * If a file system does not share extended attributes among inodes,
- * we should not need the ext3_xattr_sem semaphore. However, the
- * filesystem may still contain shared blocks, so we always take
- * the lock.
- */
-
-static DECLARE_MUTEX(ext3_xattr_sem);
 static struct ext3_xattr_handler *ext3_xattr_handlers[EXT3_XATTR_INDEX_MAX];
 static rwlock_t ext3_handler_lock = RW_LOCK_UNLOCKED;
 
@@ -192,7 +182,7 @@
 /*
  * Inode operation getxattr()
  *
- * dentry->d_inode->i_sem down
+ * dentry->d_inode->i_sem: don't care
  */
 ssize_t
 ext3_getxattr(struct dentry *dentry, const char *name,
@@ -210,7 +200,7 @@
 /*
  * Inode operation listxattr()
  *
- * dentry->d_inode->i_sem down
+ * dentry->d_inode->i_sem: don't care
  */
 ssize_t
 ext3_listxattr(struct dentry *dentry, char *buffer, size_t size)
@@ -221,7 +211,7 @@
 /*
  * Inode operation setxattr()
  *
- * dentry->d_inode->i_sem down
+ * dentry->d_inode->i_sem: down
  */
 int
 ext3_setxattr(struct dentry *dentry, const char *name,
@@ -241,7 +231,7 @@
 /*
  * Inode operation removexattr()
  *
- * dentry->d_inode->i_sem down
+ * dentry->d_inode->i_sem: down
  */
 int
 ext3_removexattr(struct dentry *dentry, const char *name)
@@ -271,21 +261,24 @@
 {
 	struct buffer_head *bh = NULL;
 	struct ext3_xattr_entry *entry;
-	unsigned int size;
+	size_t name_len, size;
 	char *end;
-	int name_len, error;
+	int error;
 
 	ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
 		  name_index, name, buffer, (long)buffer_size);
 
 	if (name == NULL)
 		return -EINVAL;
+	down_read(&EXT3_I(inode)->xattr_sem);
+	error = -ENODATA;
 	if (!EXT3_I(inode)->i_file_acl)
-		return -ENODATA;
+		goto cleanup;
 	ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
 	bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
+	error = -EIO;
 	if (!bh)
-		return -EIO;
+		goto cleanup;
 	ea_bdebug(bh, "b_count=%d, refcount=%d",
 		atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
 	end = bh->b_data + bh->b_size;
@@ -350,6 +343,7 @@
 
 cleanup:
 	brelse(bh);
+	up_read(&EXT3_I(inode)->xattr_sem);
 
 	return error;
 }
@@ -369,19 +363,22 @@
 {
 	struct buffer_head *bh = NULL;
 	struct ext3_xattr_entry *entry;
-	unsigned int size = 0;
+	size_t size = 0;
 	char *buf, *end;
 	int error;
 
 	ea_idebug(inode, "buffer=%p, buffer_size=%ld",
 		  buffer, (long)buffer_size);
 
+	down_read(&EXT3_I(inode)->xattr_sem);
+	error = 0;
 	if (!EXT3_I(inode)->i_file_acl)
-		return 0;
+		goto cleanup;
 	ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
 	bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
+	error = -EIO;
 	if (!bh)
-		return -EIO;
+		goto cleanup;
 	ea_bdebug(bh, "b_count=%d, refcount=%d",
 		atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
 	end = bh->b_data + bh->b_size;
@@ -434,6 +431,7 @@
 
 cleanup:
 	brelse(bh);
+	up_read(&EXT3_I(inode)->xattr_sem);
 
 	return error;
 }
@@ -449,11 +447,12 @@
 		return;
 
 	lock_super(sb);
-	ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh);
-	EXT3_SB(sb)->s_es->s_feature_compat |=
-		cpu_to_le32(EXT3_FEATURE_COMPAT_EXT_ATTR);
-	sb->s_dirt = 1;
-	ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh);
+	if (ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh) == 0) {
+		EXT3_SB(sb)->s_es->s_feature_compat |=
+			cpu_to_le32(EXT3_FEATURE_COMPAT_EXT_ATTR);
+		sb->s_dirt = 1;
+		ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh);
+	}
 	unlock_super(sb);
 }
 
@@ -478,8 +477,8 @@
 	struct buffer_head *bh = NULL;
 	struct ext3_xattr_header *header = NULL;
 	struct ext3_xattr_entry *here, *last;
-	unsigned int name_len;
-	int min_offs = sb->s_blocksize, not_found = 1, free, error;
+	size_t name_len, free, min_offs = sb->s_blocksize;
+	int not_found = 1, error;
 	char *end;
 
 	/*
@@ -508,8 +507,7 @@
 	name_len = strlen(name);
 	if (name_len > 255 || value_len > sb->s_blocksize)
 		return -ERANGE;
-	down(&ext3_xattr_sem);
-
+	down_write(&EXT3_I(inode)->xattr_sem);
 	if (EXT3_I(inode)->i_file_acl) {
 		/* The inode already has an extended attribute block. */
 		bh = sb_bread(sb, EXT3_I(inode)->i_file_acl);
@@ -536,7 +534,7 @@
 			if ((char *)next >= end)
 				goto bad_block;
 			if (!here->e_value_block && here->e_value_size) {
-				int offs = le16_to_cpu(here->e_value_offs);
+				size_t offs = le16_to_cpu(here->e_value_offs);
 				if (offs < min_offs)
 					min_offs = offs;
 			}
@@ -556,7 +554,7 @@
 			if ((char *)next >= end)
 				goto bad_block;
 			if (!last->e_value_block && last->e_value_size) {
-				int offs = le16_to_cpu(last->e_value_offs);
+				size_t offs = le16_to_cpu(last->e_value_offs);
 				if (offs < min_offs)
 					min_offs = offs;
 			}
@@ -580,39 +578,50 @@
 		error = 0;
 		if (value == NULL)
 			goto cleanup;
-		else
-			free -= EXT3_XATTR_LEN(name_len);
 	} else {
 		/* Request to create an existing attribute? */
 		error = -EEXIST;
 		if (flags & XATTR_CREATE)
 			goto cleanup;
 		if (!here->e_value_block && here->e_value_size) {
-			unsigned int size = le32_to_cpu(here->e_value_size);
+			size_t size = le32_to_cpu(here->e_value_size);
 
 			if (le16_to_cpu(here->e_value_offs) + size > 
 			    sb->s_blocksize || size > sb->s_blocksize)
 				goto bad_block;
 			free += EXT3_XATTR_SIZE(size);
 		}
+		free += EXT3_XATTR_LEN(name_len);
 	}
-	free -= EXT3_XATTR_SIZE(value_len);
 	error = -ENOSPC;
-	if (free < 0)
+	if (free < EXT3_XATTR_LEN(name_len) + EXT3_XATTR_SIZE(value_len))
 		goto cleanup;
 
 	/* Here we know that we can set the new attribute. */
 
 	if (header) {
+		int credits = 0;
+
+		/* assert(header == HDR(bh)); */
+		if (header->h_refcount != cpu_to_le32(1))
+			goto skip_get_write_access;
+		/* ext3_journal_get_write_access() requires an unlocked bh,
+		   which complicates things here. */
+		error = ext3_journal_get_write_access_credits(handle, bh,
+							      &credits);
+		if (error)
+			goto cleanup;
+		lock_buffer(bh);
 		if (header->h_refcount == cpu_to_le32(1)) {
 			ea_bdebug(bh, "modifying in-place");
 			ext3_xattr_cache_remove(bh);
-			error = ext3_journal_get_write_access(handle, bh);
-			if (error)
-				goto cleanup;
+			/* keep the buffer locked while modifying it. */
 		} else {
 			int offset;
 
+			unlock_buffer(bh);
+			journal_release_buffer(handle, bh, credits);
+		skip_get_write_access:
 			ea_bdebug(bh, "cloning");
 			header = kmalloc(bh->b_size, GFP_KERNEL);
 			error = -ENOMEM;
@@ -637,23 +646,36 @@
 		last = here = ENTRY(header+1);
 	}
 
+	/* Iff we are modifying the block in-place, bh is locked here. */
+
 	if (not_found) {
 		/* Insert the new name. */
-		int size = EXT3_XATTR_LEN(name_len);
-		int rest = (char *)last - (char *)here;
+		size_t size = EXT3_XATTR_LEN(name_len);
+		size_t rest = (char *)last - (char *)here;
 		memmove((char *)here + size, here, rest);
 		memset(here, 0, size);
 		here->e_name_index = name_index;
 		here->e_name_len = name_len;
 		memcpy(here->e_name, name, name_len);
 	} else {
-		/* Remove the old value. */
 		if (!here->e_value_block && here->e_value_size) {
 			char *first_val = (char *)header + min_offs;
-			int offs = le16_to_cpu(here->e_value_offs);
+			size_t offs = le16_to_cpu(here->e_value_offs);
 			char *val = (char *)header + offs;
 			size_t size = EXT3_XATTR_SIZE(
 				le32_to_cpu(here->e_value_size));
+
+			if (size == EXT3_XATTR_SIZE(value_len)) {
+				/* The old and the new value have the same
+				   size. Just replace. */
+				here->e_value_size = cpu_to_le32(value_len);
+				memset(val + size - EXT3_XATTR_PAD, 0,
+				       EXT3_XATTR_PAD); /* Clear pad bytes. */
+				memcpy(val, value, value_len);
+				goto skip_replace;
+			}
+
+			/* Remove the old value. */
 			memmove(first_val + size, first_val, val - first_val);
 			memset(first_val, 0, size);
 			here->e_value_offs = 0;
@@ -662,7 +684,7 @@
 			/* Adjust all value offsets. */
 			last = ENTRY(header+1);
 			while (!IS_LAST_ENTRY(last)) {
-				int o = le16_to_cpu(last->e_value_offs);
+				size_t o = le16_to_cpu(last->e_value_offs);
 				if (!last->e_value_block && o < offs)
 					last->e_value_offs =
 						cpu_to_le16(o + size);
@@ -670,20 +692,12 @@
 			}
 		}
 		if (value == NULL) {
-			/* Remove this attribute. */
-			if (EXT3_XATTR_NEXT(ENTRY(header+1)) == last) {
-				/* This block is now empty. */
-				error = ext3_xattr_set_handle2(handle, inode,
-							       bh, NULL);
-				goto cleanup;
-			} else {
-				/* Remove the old name. */
-				int size = EXT3_XATTR_LEN(name_len);
-				last = ENTRY((char *)last - size);
-				memmove(here, (char*)here + size,
-					(char*)last - (char*)here);
-				memset(last, 0, size);
-			}
+			/* Remove the old name. */
+			size_t size = EXT3_XATTR_LEN(name_len);
+			last = ENTRY((char *)last - size);
+			memmove(here, (char*)here + size,
+				(char*)last - (char*)here);
+			memset(last, 0, size);
 		}
 	}
 
@@ -700,15 +714,25 @@
 			memcpy(val, value, value_len);
 		}
 	}
-	ext3_xattr_rehash(header, here);
 
-	error = ext3_xattr_set_handle2(handle, inode, bh, header);
+skip_replace:
+	if (IS_LAST_ENTRY(ENTRY(header+1))) {
+		/* This block is now empty. */
+		if (bh && header == HDR(bh))
+			unlock_buffer(bh);  /* we were modifying in-place. */
+		error = ext3_xattr_set_handle2(handle, inode, bh, NULL);
+	} else {
+		ext3_xattr_rehash(header, here);
+		if (bh && header == HDR(bh))
+			unlock_buffer(bh);  /* we were modifying in-place. */
+		error = ext3_xattr_set_handle2(handle, inode, bh, header);
+	}
 
 cleanup:
 	brelse(bh);
 	if (!(bh && header == HDR(bh)))
 		kfree(header);
-	up(&ext3_xattr_sem);
+	up_write(&EXT3_I(inode)->xattr_sem);
 
 	return error;
 }
@@ -723,33 +747,34 @@
 {
 	struct super_block *sb = inode->i_sb;
 	struct buffer_head *new_bh = NULL;
-	int error;
+	int credits = 0, error;
 
 	if (header) {
-		new_bh = ext3_xattr_cache_find(inode, header);
+		new_bh = ext3_xattr_cache_find(handle, inode, header, &credits);
 		if (new_bh) {
 			/*
-			 * We found an identical block in the cache.
-			 * The old block will be released after updating
-			 * the inode.
+			 * We found an identical block in the cache. The
+			 * block returned is locked. The old block will
+			 * be released after updating the inode.
 			 */
-			ea_bdebug(new_bh, "%s block %ld",
+			ea_bdebug(new_bh, "%s block %lu",
 				(old_bh == new_bh) ? "keeping" : "reusing",
-				new_bh->b_blocknr);
+				(unsigned long) new_bh->b_blocknr);
 
 			error = -EDQUOT;
-			if (DQUOT_ALLOC_BLOCK(inode, 1))
-				goto cleanup;
-
-			error = ext3_journal_get_write_access(handle, new_bh);
-			if (error)
+			if (DQUOT_ALLOC_BLOCK(inode, 1)) {
+				unlock_buffer(new_bh);
+				journal_release_buffer(handle, new_bh, credits);
 				goto cleanup;
+			}
 			HDR(new_bh)->h_refcount = cpu_to_le32(
 				le32_to_cpu(HDR(new_bh)->h_refcount) + 1);
 			ea_bdebug(new_bh, "refcount now=%d",
 				le32_to_cpu(HDR(new_bh)->h_refcount));
+			unlock_buffer(new_bh);
 		} else if (old_bh && header == HDR(old_bh)) {
-			/* Keep this block. */
+			/* Keep this block. No need to lock the block as we
+			 * don't need to change the reference count. */
 			new_bh = old_bh;
 			get_bh(new_bh);
 			ext3_xattr_cache_insert(new_bh);
@@ -759,7 +784,7 @@
 					EXT3_SB(sb)->s_es->s_first_data_block) +
 				EXT3_I(inode)->i_block_group *
 				EXT3_BLOCKS_PER_GROUP(sb);
-			int block  = ext3_new_block(handle,
+			int block = ext3_new_block(handle,
 				inode, goal, 0, 0, &error);
 			if (error)
 				goto cleanup;
@@ -800,15 +825,14 @@
 	error = 0;
 	if (old_bh && old_bh != new_bh) {
 		/*
-		 * If there was an old block, and we are not still using it,
-		 * we now release the old block.
+		 * If there was an old block, and we are no longer using it,
+		 * release the old block.
 		*/
-		unsigned int refcount = le32_to_cpu(HDR(old_bh)->h_refcount);
-
 		error = ext3_journal_get_write_access(handle, old_bh);
 		if (error)
 			goto cleanup;
-		if (refcount == 1) {
+		lock_buffer(old_bh);
+		if (HDR(old_bh)->h_refcount == cpu_to_le32(1)) {
 			/* Free the old block. */
 			ea_bdebug(old_bh, "freeing");
 			ext3_free_blocks(handle, inode, old_bh->b_blocknr, 1);
@@ -820,12 +844,14 @@
 			ext3_forget(handle, 1, inode, old_bh,old_bh->b_blocknr);
 		} else {
 			/* Decrement the refcount only. */
-			refcount--;
-			HDR(old_bh)->h_refcount = cpu_to_le32(refcount);
+			HDR(old_bh)->h_refcount = cpu_to_le32(
+				le32_to_cpu(HDR(old_bh)->h_refcount) - 1);
 			DQUOT_FREE_BLOCK(inode, 1);
 			ext3_journal_dirty_metadata(handle, old_bh);
-			ea_bdebug(old_bh, "refcount now=%d", refcount);
+			ea_bdebug(old_bh, "refcount now=%d",
+				le32_to_cpu(HDR(old_bh)->h_refcount));
 		}
+		unlock_buffer(old_bh);
 	}
 
 cleanup:
@@ -869,12 +895,11 @@
 void
 ext3_xattr_delete_inode(handle_t *handle, struct inode *inode)
 {
-	struct buffer_head *bh;
+	struct buffer_head *bh = NULL;
 
+	down_write(&EXT3_I(inode)->xattr_sem);
 	if (!EXT3_I(inode)->i_file_acl)
-		return;
-	down(&ext3_xattr_sem);
-
+		goto cleanup;
 	bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
 	if (!bh) {
 		ext3_error(inode->i_sb, "ext3_xattr_delete_inode",
@@ -882,7 +907,6 @@
 			EXT3_I(inode)->i_file_acl);
 		goto cleanup;
 	}
-	ea_bdebug(bh, "b_count=%d", atomic_read(&(bh->b_count)));
 	if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
 	    HDR(bh)->h_blocks != cpu_to_le32(1)) {
 		ext3_error(inode->i_sb, "ext3_xattr_delete_inode",
@@ -890,13 +914,14 @@
 			EXT3_I(inode)->i_file_acl);
 		goto cleanup;
 	}
-	ext3_journal_get_write_access(handle, bh);
-	ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1);
+	if (ext3_journal_get_write_access(handle, bh) != 0)
+		goto cleanup;
+	lock_buffer(bh);
 	if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
 		ext3_xattr_cache_remove(bh);
 		ext3_free_blocks(handle, inode, EXT3_I(inode)->i_file_acl, 1);
+		get_bh(bh);
 		ext3_forget(handle, 1, inode, bh, EXT3_I(inode)->i_file_acl);
-		bh = NULL;
 	} else {
 		HDR(bh)->h_refcount = cpu_to_le32(
 			le32_to_cpu(HDR(bh)->h_refcount) - 1);
@@ -905,11 +930,13 @@
 			handle->h_sync = 1;
 		DQUOT_FREE_BLOCK(inode, 1);
 	}
+	ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1);
+	unlock_buffer(bh);
 	EXT3_I(inode)->i_file_acl = 0;
 
 cleanup:
 	brelse(bh);
-	up(&ext3_xattr_sem);
+	up_write(&EXT3_I(inode)->xattr_sem);
 }
 
 /*
@@ -1005,7 +1032,8 @@
  * not found or an error occurred.
  */
 static struct buffer_head *
-ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header)
+ext3_xattr_cache_find(handle_t *handle, struct inode *inode,
+		      struct ext3_xattr_header *header, int *credits)
 {
 	__u32 hash = le32_to_cpu(header->h_hash);
 	struct mb_cache_entry *ce;
@@ -1013,7 +1041,8 @@
 	if (!header->h_hash)
 		return NULL;  /* never share */
 	ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
-	ce = mb_cache_entry_find_first(ext3_xattr_cache, 0, inode->i_bdev, hash);
+	ce = mb_cache_entry_find_first(ext3_xattr_cache, 0,
+				       inode->i_sb->s_bdev, hash);
 	while (ce) {
 		struct buffer_head *bh = sb_bread(inode->i_sb, ce->e_block);
 
@@ -1021,19 +1050,29 @@
 			ext3_error(inode->i_sb, "ext3_xattr_cache_find",
 				"inode %ld: block %ld read error",
 				inode->i_ino, (unsigned long) ce->e_block);
-		} else if (le32_to_cpu(HDR(bh)->h_refcount) >
-			   EXT3_XATTR_REFCOUNT_MAX) {
-			ea_idebug(inode, "block %ld refcount %d>%d",
-				  (unsigned long) ce->e_block,
-				  le32_to_cpu(HDR(bh)->h_refcount),
-				  EXT3_XATTR_REFCOUNT_MAX);
-		} else if (!ext3_xattr_cmp(header, HDR(bh))) {
-			ea_bdebug(bh, "b_count=%d",atomic_read(&(bh->b_count)));
-			mb_cache_entry_release(ce);
-			return bh;
+		} else {
+			/* ext3_journal_get_write_access() requires an unlocked
+			 * bh, which complicates things here. */
+			if (ext3_journal_get_write_access_credits(handle, bh,
+								  credits) != 0)
+				return NULL;
+			lock_buffer(bh);
+			if (le32_to_cpu(HDR(bh)->h_refcount) >
+				   EXT3_XATTR_REFCOUNT_MAX) {
+				ea_idebug(inode, "block %ld refcount %d>%d",
+					  (unsigned long) ce->e_block,
+					  le32_to_cpu(HDR(bh)->h_refcount),
+					  EXT3_XATTR_REFCOUNT_MAX);
+			} else if (!ext3_xattr_cmp(header, HDR(bh))) {
+				mb_cache_entry_release(ce);
+				/* buffer will be unlocked by caller */
+				return bh;
+			}
+			unlock_buffer(bh);
+			journal_release_buffer(handle, bh, *credits);
+			brelse(bh);
 		}
-		brelse(bh);
-		ce = mb_cache_entry_find_next(ce, 0, inode->i_bdev, hash);
+		ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash);
 	}
 	return NULL;
 }
diff -urN linux-2.5.74-bk4/fs/ext3/xattr_user.c linux-2.5.74-bk5/fs/ext3/xattr_user.c
--- linux-2.5.74-bk4/fs/ext3/xattr_user.c	2003-07-07 04:56:57.000000000 -0700
+++ linux-2.5.74-bk5/fs/ext3/xattr_user.c	2003-07-07 04:57:17.000000000 -0700
@@ -13,10 +13,6 @@
 #include <linux/ext3_fs.h>
 #include "xattr.h"
 
-#ifdef CONFIG_EXT3_FS_POSIX_ACL
-# include "acl.h"
-#endif
-
 #define XATTR_USER_PREFIX "user."
 
 static size_t
@@ -46,11 +42,7 @@
 		return -EINVAL;
 	if (!test_opt(inode->i_sb, XATTR_USER))
 		return -EOPNOTSUPP;
-#ifdef CONFIG_EXT3_FS_POSIX_ACL
-	error = ext3_permission_locked(inode, MAY_READ);
-#else
 	error = permission(inode, MAY_READ, NULL);
-#endif
 	if (error)
 		return error;
 
@@ -70,11 +62,7 @@
 	if ( !S_ISREG(inode->i_mode) &&
 	    (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
 		return -EPERM;
-#ifdef CONFIG_EXT3_FS_POSIX_ACL
-	error = ext3_permission_locked(inode, MAY_WRITE);
-#else
 	error = permission(inode, MAY_WRITE, NULL);
-#endif
 	if (error)
 		return error;
 
diff -urN linux-2.5.74-bk4/fs/jfs/xattr.c linux-2.5.74-bk5/fs/jfs/xattr.c
--- linux-2.5.74-bk4/fs/jfs/xattr.c	2003-07-07 04:56:58.000000000 -0700
+++ linux-2.5.74-bk5/fs/jfs/xattr.c	2003-07-07 04:57:18.000000000 -0700
@@ -964,10 +964,17 @@
 ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data,
 		     size_t buf_size)
 {
-	return __jfs_getxattr(dentry->d_inode, name, data, buf_size);
+	int err;
+
+	down(&dentry->d_inode->i_sem);
+	err = __jfs_getxattr(dentry->d_inode, name, data, buf_size);
+	up(&dentry->d_inode->i_sem);
+
+	return err;
 }
 
-ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size)
+static ssize_t __jfs_listxattr(struct dentry * dentry, char *data,
+			       size_t buf_size)
 {
 	struct inode *inode = dentry->d_inode;
 	char *buffer;
@@ -1013,6 +1020,17 @@
 	return size;
 }
 
+ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size)
+{
+	int err;
+
+	down(&dentry->d_inode->i_sem);
+	err = __jfs_listxattr(dentry, data, buf_size);
+	up(&dentry->d_inode->i_sem);
+
+	return err;
+}
+
 int jfs_removexattr(struct dentry *dentry, const char *name)
 {
 	return __jfs_setxattr(dentry->d_inode, name, 0, 0, XATTR_REPLACE);
diff -urN linux-2.5.74-bk4/fs/proc/base.c linux-2.5.74-bk5/fs/proc/base.c
--- linux-2.5.74-bk4/fs/proc/base.c	2003-07-07 04:56:58.000000000 -0700
+++ linux-2.5.74-bk5/fs/proc/base.c	2003-07-07 04:57:19.000000000 -0700
@@ -1245,7 +1245,9 @@
 	.readdir	= proc_attr_readdir,
 };
 
-static struct dentry *proc_attr_lookup(struct inode *dir, struct dentry *dentry){
+static struct dentry *proc_attr_lookup(struct inode *dir,
+				struct dentry *dentry, struct nameidata *nd)
+{
 	return proc_pident_lookup(dir, dentry, attr_stuff);
 }
 
diff -urN linux-2.5.74-bk4/fs/xattr.c linux-2.5.74-bk5/fs/xattr.c
--- linux-2.5.74-bk4/fs/xattr.c	2003-07-02 13:46:18.000000000 -0700
+++ linux-2.5.74-bk5/fs/xattr.c	2003-07-07 04:57:20.000000000 -0700
@@ -160,9 +160,7 @@
 		error = security_inode_getxattr(d, kname);
 		if (error)
 			goto out;
-		down(&d->d_inode->i_sem);
 		error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
-		up(&d->d_inode->i_sem);
 	}
 
 	if (kvalue && error > 0)
@@ -233,9 +231,7 @@
 		error = security_inode_listxattr(d);
 		if (error)
 			goto out;
-		down(&d->d_inode->i_sem);
 		error = d->d_inode->i_op->listxattr(d, klist, size);
-		up(&d->d_inode->i_sem);
 	}
 
 	if (klist && error > 0)
diff -urN linux-2.5.74-bk4/fs/xfs/linux/xfs_iops.c linux-2.5.74-bk5/fs/xfs/linux/xfs_iops.c
--- linux-2.5.74-bk4/fs/xfs/linux/xfs_iops.c	2003-07-07 04:56:59.000000000 -0700
+++ linux-2.5.74-bk5/fs/xfs/linux/xfs_iops.c	2003-07-07 04:57:20.000000000 -0700
@@ -642,7 +642,7 @@
 }
 
 STATIC ssize_t
-linvfs_getxattr(
+__linvfs_getxattr(
 	struct dentry	*dentry,
 	const char	*name,
 	void		*data,
@@ -697,9 +697,24 @@
 	return -EOPNOTSUPP;
 }
 
+STATIC ssize_t
+linvfs_getxattr(
+	struct dentry	*dentry,
+	const char	*name,
+	void		*data,
+	size_t		size)
+{
+	int error;
+
+	down(&dentry->d_inode->i_sem);
+	error = __linvfs_getxattr(dentry, name, data, size);
+	up(&dentry->d_inode->i_sem);
+
+	return error;
+}
 
 STATIC ssize_t
-linvfs_listxattr(
+__linvfs_listxattr(
 	struct dentry		*dentry,
 	char			*data,
 	size_t			size)
@@ -741,6 +756,21 @@
 	return result;
 }
 
+STATIC ssize_t
+linvfs_listxattr(
+	struct dentry		*dentry,
+	char			*data,
+	size_t			size)
+{
+	int error;
+
+	down(&dentry->d_inode->i_sem);
+	error = __linvfs_listxattr(dentry, data, size);
+	up(&dentry->d_inode->i_sem);
+
+	return error;
+}
+
 STATIC int
 linvfs_removexattr(
 	struct dentry	*dentry,
diff -urN linux-2.5.74-bk4/fs/xfs/linux/xfs_super.c linux-2.5.74-bk5/fs/xfs/linux/xfs_super.c
--- linux-2.5.74-bk4/fs/xfs/linux/xfs_super.c	2003-07-02 13:55:56.000000000 -0700
+++ linux-2.5.74-bk5/fs/xfs/linux/xfs_super.c	2003-07-07 04:57:20.000000000 -0700
@@ -265,8 +265,8 @@
 
 	if (set_blocksize(btp->pbr_bdev, sectorsize)) {
 		printk(KERN_WARNING
-			"XFS: Cannot set_blocksize to %u on device 0x%x\n",
-			sectorsize, btp->pbr_dev);
+			"XFS: Cannot set_blocksize to %u on device 0x%lx\n",
+			sectorsize, (unsigned long)btp->pbr_dev);
 	}
 }
 
diff -urN linux-2.5.74-bk4/include/asm-alpha/div64.h linux-2.5.74-bk5/include/asm-alpha/div64.h
--- linux-2.5.74-bk4/include/asm-alpha/div64.h	2003-07-02 13:54:43.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-alpha/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -1,14 +1 @@
-#ifndef __ALPHA_DIV64
-#define __ALPHA_DIV64
-
-/*
- * Hey, we're already 64-bit, no
- * need to play games..
- */
-#define do_div(n,base) ({ \
-	int __res; \
-	__res = ((unsigned long) (n)) % (unsigned) (base); \
-	(n) = ((unsigned long) (n)) / (unsigned) (base); \
-	__res; })
-
-#endif
+#include <asm-generic/div64.h>
diff -urN linux-2.5.74-bk4/include/asm-arm26/div64.h linux-2.5.74-bk5/include/asm-arm26/div64.h
--- linux-2.5.74-bk4/include/asm-arm26/div64.h	2003-07-02 13:42:11.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-arm26/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -1,14 +1 @@
-#ifndef __ASM_ARM_DIV64
-#define __ASM_ARM_DIV64
-
-/* We're not 64-bit, but... */
-#define do_div(n,base)						\
-({								\
-	int __res;						\
-	__res = ((unsigned long)n) % (unsigned int)base;	\
-	n = ((unsigned long)n) / (unsigned int)base;		\
-	__res;							\
-})
-
-#endif
-
+#include <asm-generic/div64.h>
diff -urN linux-2.5.74-bk4/include/asm-cris/div64.h linux-2.5.74-bk5/include/asm-cris/div64.h
--- linux-2.5.74-bk4/include/asm-cris/div64.h	2003-07-02 13:42:06.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-cris/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -1,16 +1 @@
-#ifndef __ASM_CRIS_DIV64
-#define __ASM_CRIS_DIV64
-
-/* copy from asm-arm */
-
-/* We're not 64-bit, but... */
-#define do_div(n,base)						\
-({								\
-	int __res;						\
-	__res = ((unsigned long)n) % (unsigned int)base;	\
-	n = ((unsigned long)n) / (unsigned int)base;		\
-	__res;							\
-})
-
-#endif
-
+#include <asm-generic/div64.h>
diff -urN linux-2.5.74-bk4/include/asm-generic/div64.h linux-2.5.74-bk5/include/asm-generic/div64.h
--- linux-2.5.74-bk4/include/asm-generic/div64.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.5.74-bk5/include/asm-generic/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -0,0 +1,53 @@
+#ifndef _ASM_GENERIC_DIV64_H
+#define _ASM_GENERIC_DIV64_H
+/*
+ * Copyright (C) 2003 Bernardo Innocenti <bernie@develer.com>
+ * Based on former asm-ppc/div64.h and asm-m68knommu/div64.h
+ *
+ * The semantics of do_div() are:
+ *
+ * uint32_t do_div(uint64_t *n, uint32_t base)
+ * {
+ * 	uint32_t remainder = *n % base;
+ * 	*n = *n / base;
+ * 	return remainder;
+ * }
+ *
+ * NOTE: macro parameter n is evaluated multiple times,
+ *       beware of side effects!
+ */
+
+#include <linux/types.h>
+
+#if BITS_PER_LONG == 64
+
+# define do_div(n,base) ({					\
+	uint32_t __base = (base);				\
+	uint32_t __rem;						\
+	__rem = ((uint64_t)(n)) % __base;			\
+	(n) = ((uint64_t)(n)) / __base;				\
+	__rem;							\
+ })
+
+#elif BITS_PER_LONG == 32
+
+extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
+
+# define do_div(n,base) ({				\
+	uint32_t __base = (base);			\
+	uint32_t __rem;					\
+	if (((n) >> 32) == 0) {				\
+		__rem = (uint32_t)(n) % __base;		\
+		(n) = (uint32_t)(n) / __base;		\
+	} else 						\
+		__rem = __div64_32(&(n), __base);	\
+	__rem;						\
+ })
+
+#else /* BITS_PER_LONG == ?? */
+
+# error do_div() does not yet support the C64
+
+#endif /* BITS_PER_LONG */
+
+#endif /* _ASM_GENERIC_DIV64_H */
diff -urN linux-2.5.74-bk4/include/asm-h8300/div64.h linux-2.5.74-bk5/include/asm-h8300/div64.h
--- linux-2.5.74-bk4/include/asm-h8300/div64.h	2003-07-02 13:39:25.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-h8300/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -1,13 +1 @@
-#ifndef H8300_DIV64_H
-#define H8300_DIV64_H
-
-/* n = n / base; return rem; */
-
-#define do_div(n,base) ({					\
-	int __res;						\
-	__res = ((unsigned long) n) % (unsigned) base;		\
-	n = ((unsigned long) n) / (unsigned) base;		\
-	__res;							\
-})
-
-#endif /* _H8300_DIV64_H */
+#include <asm-generic/div64.h>
diff -urN linux-2.5.74-bk4/include/asm-h8300/flat.h linux-2.5.74-bk5/include/asm-h8300/flat.h
--- linux-2.5.74-bk4/include/asm-h8300/flat.h	2003-07-02 13:39:16.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-h8300/flat.h	2003-07-07 04:57:20.000000000 -0700
@@ -5,6 +5,21 @@
 #ifndef __H8300_FLAT_H__
 #define __H8300_FLAT_H__
 
-#define flat_argvp_envp_on_stack()	1
+#define	flat_stack_align(sp)			/* nothing needed */
+#define	flat_argvp_envp_on_stack()		1
+#define	flat_old_ram_flag(flags)		1
+#define	flat_reloc_valid(reloc, size)		((reloc) <= (size))
+
+/*
+ * on the H8 a couple of the relocations have an instruction in the
+ * top byte.  As there can only be 24bits of address space,  we just
+ * always preserve that 8bits at the top,  when it isn't an instruction
+ * is is 0 (davidm@snapgear.com)
+ */
+
+#define	flat_get_relocate_addr(rel)		(rel)
+#define flat_get_addr_from_rp(rp, relval)       (get_unaligned(rp) & 0x0ffffff)
+#define flat_put_addr_at_rp(rp, addr, rel) \
+	put_unaligned (((*(char *)(rp)) << 24) | ((addr) & 0x00ffffff), rp)
 
 #endif /* __H8300_FLAT_H__ */
diff -urN linux-2.5.74-bk4/include/asm-ia64/div64.h linux-2.5.74-bk5/include/asm-ia64/div64.h
--- linux-2.5.74-bk4/include/asm-ia64/div64.h	2003-07-02 13:58:14.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-ia64/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -1,20 +1 @@
-#ifndef _ASM_IA64_DIV64_H
-#define _ASM_IA64_DIV64_H
-
-/*
- * Copyright (C) 1999 Hewlett-Packard Co
- * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * vsprintf uses this to divide a 64-bit integer N by a small integer BASE.
- * This is incredibly hard on IA-64...
- */
-
-#define do_div(n,base)						\
-({								\
-	int _res;						\
-	_res = ((unsigned long) (n)) % (unsigned) (base);	\
-	(n) = ((unsigned long) (n)) / (unsigned) (base);	\
-	_res;							\
-})
-
-#endif /* _ASM_IA64_DIV64_H */
+#include <asm-generic/div64.h>
diff -urN linux-2.5.74-bk4/include/asm-m68k/div64.h linux-2.5.74-bk5/include/asm-m68k/div64.h
--- linux-2.5.74-bk4/include/asm-m68k/div64.h	2003-07-02 13:55:53.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-m68k/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -3,7 +3,6 @@
 
 /* n = n / base; return rem; */
 
-#if 1
 #define do_div(n, base) ({					\
 	union {							\
 		unsigned long n32[2];				\
@@ -23,13 +22,5 @@
 	(n) = __n.n64;						\
 	__rem;							\
 })
-#else
-#define do_div(n,base) ({					\
-	int __res;						\
-	__res = ((unsigned long) n) % (unsigned) base;		\
-	n = ((unsigned long) n) / (unsigned) base;		\
-	__res;							\
-})
-#endif
 
 #endif /* _M68K_DIV64_H */
diff -urN linux-2.5.74-bk4/include/asm-m68knommu/div64.h linux-2.5.74-bk5/include/asm-m68knommu/div64.h
--- linux-2.5.74-bk4/include/asm-m68knommu/div64.h	2003-07-02 13:43:22.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-m68knommu/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -1,13 +1 @@
-#ifndef _M68KNOMMU_DIV64_H
-#define _M68KNOMMU_DIV64_H
-
-/* n = n / base; return rem; */
-
-#define do_div(n,base) ({					\
-	int __res;						\
-	__res = ((unsigned long) n) % (unsigned) base;		\
-	n = ((unsigned long) n) / (unsigned) base;		\
-	__res;							\
-})
-
-#endif /* _M68K_DIV64_H */
+#include <asm-generic/div64.h>
diff -urN linux-2.5.74-bk4/include/asm-m68knommu/flat.h linux-2.5.74-bk5/include/asm-m68knommu/flat.h
--- linux-2.5.74-bk4/include/asm-m68knommu/flat.h	2003-07-02 13:55:52.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-m68knommu/flat.h	2003-07-07 04:57:20.000000000 -0700
@@ -5,6 +5,12 @@
 #ifndef __M68KNOMMU_FLAT_H__
 #define __M68KNOMMU_FLAT_H__
 
-#define flat_argvp_envp_on_stack()	1
+#define	flat_stack_align(sp)			/* nothing needed */
+#define	flat_argvp_envp_on_stack()		1
+#define	flat_old_ram_flag(flags)		(flags)
+#define	flat_reloc_valid(reloc, size)		((reloc) <= (size))
+#define	flat_get_addr_from_rp(rp, relval)	get_unaligned(rp)
+#define	flat_put_addr_at_rp(rp, val, relval)	put_unaligned(val,rp)
+#define	flat_get_relocate_addr(rel)		(rel)
 
 #endif /* __M68KNOMMU_FLAT_H__ */
diff -urN linux-2.5.74-bk4/include/asm-m68knommu/page.h linux-2.5.74-bk5/include/asm-m68knommu/page.h
--- linux-2.5.74-bk4/include/asm-m68knommu/page.h	2003-07-02 13:46:48.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-m68knommu/page.h	2003-07-07 04:57:20.000000000 -0700
@@ -6,7 +6,7 @@
 /* PAGE_SHIFT determines the page size */
 
 #define PAGE_SHIFT	(12)
-#define PAGE_SIZE	(4096)
+#define PAGE_SIZE	(1UL << PAGE_SHIFT)
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 
 #ifdef __KERNEL__
diff -urN linux-2.5.74-bk4/include/asm-m68knommu/semaphore.h linux-2.5.74-bk5/include/asm-m68knommu/semaphore.h
--- linux-2.5.74-bk4/include/asm-m68knommu/semaphore.h	2003-07-02 13:49:36.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-m68knommu/semaphore.h	2003-07-07 04:57:20.000000000 -0700
@@ -145,7 +145,7 @@
 		".previous"
 		: "=d" (result)
 		: "a" (sem1)
-		: "%d0", "memory");
+		: "memory");
 	return result;
 }
 
diff -urN linux-2.5.74-bk4/include/asm-m68knommu/uaccess.h linux-2.5.74-bk5/include/asm-m68knommu/uaccess.h
--- linux-2.5.74-bk4/include/asm-m68knommu/uaccess.h	2003-07-02 13:51:42.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-m68knommu/uaccess.h	2003-07-07 04:57:20.000000000 -0700
@@ -13,21 +13,14 @@
 #define VERIFY_READ	0
 #define VERIFY_WRITE	1
 
-/* We let the MMU do all checking */
-extern inline int access_ok(int type, const void * addr, unsigned long size)
+#define access_ok(type,addr,size)	_access_ok((unsigned long)(addr),(size))
+
+static inline int _access_ok(unsigned long addr, unsigned long size)
 {
-#define	RANGE_CHECK_OK(addr, size, lower, upper) \
-	(((addr) >= (lower)) && (((addr) + (size)) < (upper)))
+	extern unsigned long memory_start, memory_end;
 
-#ifdef CONFIG_COLDFIRE
-	extern unsigned long _ramend;
-	return(RANGE_CHECK_OK((unsigned long) addr, size, 0L, _ramend) ||
-			(is_in_rom((unsigned long) addr) &&
-					is_in_rom((unsigned long) addr + size)));
-#else
-	/* DAVIDM - this could be restricted a lot more */
-	return(RANGE_CHECK_OK((unsigned long)addr, size, 0, 0x10f00000));
-#endif
+	return (((addr >= memory_start) && (addr+size < memory_end)) ||
+		(is_in_rom(addr) && is_in_rom(addr+size)));
 }
 
 extern inline int verify_area(int type, const void * addr, unsigned long size)
diff -urN linux-2.5.74-bk4/include/asm-mips64/div64.h linux-2.5.74-bk5/include/asm-mips64/div64.h
--- linux-2.5.74-bk4/include/asm-mips64/div64.h	2003-07-02 13:47:26.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-mips64/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -27,23 +27,6 @@
 	(res) = __quot; \
 	__mod; })
 
-/*
- * Hey, we're already 64-bit, no
- * need to play games..
- */
-#define do_div(n, base) ({ \
-	unsigned long __quot; \
-	unsigned int __mod; \
-	unsigned long __div; \
-	unsigned int __base; \
-	\
-	__div = (n); \
-	__base = (base); \
-	\
-	__mod = __div % __base; \
-	__quot = __div / __base; \
-	\
-	(n) = __quot; \
-	__mod; })
+#include <asm-generic.h>
 
 #endif /* _ASM_DIV64_H */
diff -urN linux-2.5.74-bk4/include/asm-parisc/div64.h linux-2.5.74-bk5/include/asm-parisc/div64.h
--- linux-2.5.74-bk4/include/asm-parisc/div64.h	2003-07-02 13:48:40.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-parisc/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -1,54 +1 @@
-#ifndef __ASM_PARISC_DIV64
-#define __ASM_PARISC_DIV64
-
-#ifdef __LP64__
-
-/*
- * Copyright (C) 1999 Hewlett-Packard Co
- * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * vsprintf uses this to divide a 64-bit integer N by a small integer BASE.
- * This is incredibly hard on IA-64 and HPPA
- */
-
-#define do_div(n,base)						\
-({								\
-	int _res;						\
-	_res = ((unsigned long) (n)) % (unsigned) (base);	\
-	(n) = ((unsigned long) (n)) / (unsigned) (base);	\
-	_res;							\
-})
-
-#else
-/*
- * unsigned long long division.  Yuck Yuck!  What is Linux coming to?
- * This is 100% disgusting
- */
-#define do_div(n,base)							\
-({									\
-	unsigned long __low, __low2, __high, __rem;			\
-	__low  = (n) & 0xffffffff;					\
-	__high = (n) >> 32;						\
-	if (__high) {							\
-		__rem   = __high % (unsigned long)base;			\
-		__high  = __high / (unsigned long)base;			\
-		__low2  = __low >> 16;					\
-		__low2 += __rem << 16;					\
-		__rem   = __low2 % (unsigned long)base;			\
-		__low2  = __low2 / (unsigned long)base;			\
-		__low   = __low & 0xffff;				\
-		__low  += __rem << 16;					\
-		__rem   = __low  % (unsigned long)base;			\
-		__low   = __low  / (unsigned long)base;			\
-		n = __low  + ((long long)__low2 << 16) +		\
-			((long long) __high << 32);			\
-	} else {							\
-		__rem = __low % (unsigned long)base;			\
-		n = (__low / (unsigned long)base);			\
-	}								\
-	__rem;								\
-})
-#endif
-
-#endif
-
+#include <asm-generic/div64.h>
diff -urN linux-2.5.74-bk4/include/asm-ppc/div64.h linux-2.5.74-bk5/include/asm-ppc/div64.h
--- linux-2.5.74-bk4/include/asm-ppc/div64.h	2003-07-02 13:57:06.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-ppc/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -1,23 +1 @@
-#ifndef __PPC_DIV64
-#define __PPC_DIV64
-
-#include <linux/types.h>
-
-extern u32 __div64_32(u64 *dividend, u32 div);
-
-#define do_div(n, div)	({			\
-	u64 __n = (n);				\
-	u32 __d = (div);			\
-	u32 __q, __r;				\
-	if ((__n >> 32) == 0) {			\
-		__q = (u32)__n / __d;		\
-		__r = (u32)__n - __q * __d;	\
-		(n) = __q;			\
-	} else {				\
-		__r = __div64_32(&__n, __d);	\
-		(n) = __n;			\
-	}					\
-	__r;					\
-})
-
-#endif
+#include <asm-generic/div64.h>
diff -urN linux-2.5.74-bk4/include/asm-ppc64/div64.h linux-2.5.74-bk5/include/asm-ppc64/div64.h
--- linux-2.5.74-bk4/include/asm-ppc64/div64.h	2003-07-02 13:39:34.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-ppc64/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -1,18 +1 @@
-#ifndef __PPC_DIV64
-#define __PPC_DIV64
-
-/* Copyright 2001 PPC64 Team, IBM Corp
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#define do_div(n,base) ({ \
-	int __res; \
-	__res = ((unsigned long) (n)) % (unsigned) (base); \
-	(n) = ((unsigned long) (n)) / (unsigned) (base); \
-	__res; })
-
-#endif
+#include <asm-generic/div64.h>
diff -urN linux-2.5.74-bk4/include/asm-s390/div64.h linux-2.5.74-bk5/include/asm-s390/div64.h
--- linux-2.5.74-bk4/include/asm-s390/div64.h	2003-07-02 13:50:17.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-s390/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -43,13 +43,7 @@
 })
 
 #else /* __s390x__ */
-
-#define do_div(n,base) ({ \
-int __res; \
-__res = ((unsigned long) n) % (unsigned) base; \
-n = ((unsigned long) n) / (unsigned) base; \
-__res; })
-
+#include <asm-generic/div64.h>
 #endif /* __s390x__ */
 
 #endif
diff -urN linux-2.5.74-bk4/include/asm-sh/div64.h linux-2.5.74-bk5/include/asm-sh/div64.h
--- linux-2.5.74-bk4/include/asm-sh/div64.h	2003-07-02 13:39:36.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-sh/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -1,20 +1 @@
-#ifndef __ASM_SH_DIV64
-#define __ASM_SH_DIV64
-
-extern u64 __div64_32(u64 n, u32 d);
-
-#define do_div(n,base) ({ \
-u64 __n = (n), __q; \
-u32 __base = (base); \
-u32 __res; \
-if ((__n >> 32) == 0) { \
-	__res = ((unsigned long) __n) % (unsigned) __base; \
-	(n) = ((unsigned long) __n) / (unsigned) __base; \
-} else { \
-	__q = __div64_32(__n, __base); \
-	__res = __n - __q * __base; \
-	(n) = __q; \
-} \
-__res; })
-
-#endif /* __ASM_SH_DIV64 */
+#include <asm-generic/div64.h>
diff -urN linux-2.5.74-bk4/include/asm-sparc/div64.h linux-2.5.74-bk5/include/asm-sparc/div64.h
--- linux-2.5.74-bk4/include/asm-sparc/div64.h	2003-07-02 13:51:01.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-sparc/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -1,11 +1 @@
-#ifndef __SPARC_DIV64
-#define __SPARC_DIV64
-
-/* We're not 64-bit, but... */
-#define do_div(n,base) ({ \
-	int __res; \
-	__res = ((unsigned long) n) % (unsigned) base; \
-	n = ((unsigned long) n) / (unsigned) base; \
-	__res; })
-
-#endif /* __SPARC_DIV64 */
+#include <asm-generic/div64.h>
diff -urN linux-2.5.74-bk4/include/asm-sparc64/div64.h linux-2.5.74-bk5/include/asm-sparc64/div64.h
--- linux-2.5.74-bk4/include/asm-sparc64/div64.h	2003-07-02 13:46:06.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-sparc64/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -1,14 +1 @@
-#ifndef __SPARC64_DIV64
-#define __SPARC64_DIV64
-
-/*
- * Hey, we're already 64-bit, no
- * need to play games..
- */
-#define do_div(n,base) ({ \
-	int __res; \
-	__res = ((unsigned long) n) % (unsigned) base; \
-	n = ((unsigned long) n) / (unsigned) base; \
-	__res; })
-
-#endif /* __SPARC64_DIV64 */
+#include <asm-generic/div64.h>
diff -urN linux-2.5.74-bk4/include/asm-v850/div64.h linux-2.5.74-bk5/include/asm-v850/div64.h
--- linux-2.5.74-bk4/include/asm-v850/div64.h	2003-07-02 13:53:46.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-v850/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -1,11 +1 @@
-#ifndef __V850_DIV64_H__
-#define __V850_DIV64_H__
-
-/* We're not 64-bit, but... */
-#define do_div(n,base) ({ \
-	int __res; \
-	__res = ((unsigned long) n) % (unsigned) base; \
-	n = ((unsigned long) n) / (unsigned) base; \
-	__res; })
-
-#endif /* __V850_DIV64_H__ */
+#include <asm-generic/div64.h>
diff -urN linux-2.5.74-bk4/include/asm-v850/flat.h linux-2.5.74-bk5/include/asm-v850/flat.h
--- linux-2.5.74-bk4/include/asm-v850/flat.h	2003-07-02 13:43:58.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-v850/flat.h	2003-07-07 04:57:20.000000000 -0700
@@ -1,8 +1,8 @@
 /*
  * include/asm-v850/flat.h -- uClinux flat-format executables
  *
- *  Copyright (C) 2002  NEC Corporation
- *  Copyright (C) 2002  Miles Bader <miles@gnu.org>
+ *  Copyright (C) 2002,03  NEC Electronics Corporation
+ *  Copyright (C) 2002,03  Miles Bader <miles@gnu.org>
  *
  * This file is subject to the terms and conditions of the GNU General
  * Public License.  See the file COPYING in the main directory of this
@@ -14,6 +14,117 @@
 #ifndef __V850_FLAT_H__
 #define __V850_FLAT_H__
 
-#define flat_argvp_envp_on_stack()	0
+/* The amount by which a relocation can exceed the program image limits
+   without being regarded as an error.  On the v850, the relocations of
+   some base-pointers can be offset by 0x8000 (to allow better usage of the
+   space offered by 16-bit signed offsets -- in most cases the offsets used
+   with such a base-pointer will be negative).  */
+
+#define	flat_reloc_valid(reloc, size)	((reloc) <= (size + 0x8000))
+
+#define	flat_stack_align(sp)		/* nothing needed */
+#define	flat_argvp_envp_on_stack()	0
+#define	flat_old_ram_flag(flags)	(flags)
+
+/* We store the type of relocation in the top 4 bits of the `relval.' */
+
+/* Convert a relocation entry into an address.  */
+static inline unsigned long
+flat_get_relocate_addr (unsigned long relval)
+{
+	return relval & 0x0fffffff; /* Mask out top 4-bits */
+}
+
+#define flat_v850_get_reloc_type(relval) ((relval) >> 28)
+
+#define FLAT_V850_R_32		0 /* Normal 32-bit reloc */
+#define FLAT_V850_R_HI16S_LO15	1 /* High 16-bits + signed 15-bit low field */
+#define FLAT_V850_R_HI16S_LO16	2 /* High 16-bits + signed 16-bit low field */
+
+/* Extract the address to be relocated from the symbol reference at RP;
+   RELVAL is the raw relocation-table entry from which RP is derived.
+   For the v850, RP should always be half-word aligned.  */
+static inline unsigned long flat_get_addr_from_rp (unsigned long *rp,
+						   unsigned long relval)
+{
+	short *srp = (short *)rp;
+
+	switch (flat_v850_get_reloc_type (relval))
+	{
+	case FLAT_V850_R_32:
+		/* Simple 32-bit address.  */
+		return srp[0] | (srp[1] << 16);
+
+	case FLAT_V850_R_HI16S_LO16:
+		/* The high and low halves of the address are in the 16
+		   bits at RP, and the 2nd word of the 32-bit instruction
+		   following that, respectively.  The low half is _signed_
+		   so we have to sign-extend it and add it to the upper
+		   half instead of simply or-ing them together.
+
+		   Unlike most relocated address, this one is stored in
+		   native (little-endian) byte-order to avoid problems with
+		   trashing the low-order bit, so we have to convert to
+		   network-byte-order before returning, as that's what the
+		   caller expects.  */
+		return htonl ((srp[0] << 16) + srp[2]);
+
+	case FLAT_V850_R_HI16S_LO15:
+		/* The high and low halves of the address are in the 16
+		   bits at RP, and the upper 15 bits of the 2nd word of the
+		   32-bit instruction following that, respectively.  The
+		   low half is _signed_ so we have to sign-extend it and
+		   add it to the upper half instead of simply or-ing them
+		   together.  The lowest bit is always zero.
+
+		   Unlike most relocated address, this one is stored in
+		   native (little-endian) byte-order to avoid problems with
+		   trashing the low-order bit, so we have to convert to
+		   network-byte-order before returning, as that's what the
+		   caller expects.  */
+		return htonl ((srp[0] << 16) + (srp[2] & ~0x1));
+
+	default:
+		return ~0;	/* bogus value */
+	}
+}
+
+/* Insert the address ADDR into the symbol reference at RP;
+   RELVAL is the raw relocation-table entry from which RP is derived.
+   For the v850, RP should always be half-word aligned.  */
+static inline void flat_put_addr_at_rp (unsigned long *rp, unsigned long addr,
+					unsigned long relval)
+{
+	short *srp = (short *)rp;
+
+	switch (flat_v850_get_reloc_type (relval)) {
+	case FLAT_V850_R_32:
+		/* Simple 32-bit address.  */
+		srp[0] = addr & 0xFFFF;
+		srp[1] = (addr >> 16);
+		break;
+
+	case FLAT_V850_R_HI16S_LO16:
+		/* The high and low halves of the address are in the 16
+		   bits at RP, and the 2nd word of the 32-bit instruction
+		   following that, respectively.  The low half is _signed_
+		   so we must carry its sign bit to the upper half before
+		   writing the upper half.  */
+		srp[0] = (addr >> 16) + ((addr >> 15) & 0x1);
+		srp[2] = addr & 0xFFFF;
+		break;
+
+	case FLAT_V850_R_HI16S_LO15:
+		/* The high and low halves of the address are in the 16
+		   bits at RP, and the upper 15 bits of the 2nd word of the
+		   32-bit instruction following that, respectively.  The
+		   low half is _signed_ so we must carry its sign bit to
+		   the upper half before writing the upper half.  The
+		   lowest bit we preserve from the existing instruction.  */
+		srp[0] = (addr >> 16) + ((addr >> 15) & 0x1);
+		srp[2] = (addr & 0xFFFE) | (srp[2] & 0x1);
+		break;
+	}
+}
 
 #endif /* __V850_FLAT_H__ */
diff -urN linux-2.5.74-bk4/include/asm-x86_64/div64.h linux-2.5.74-bk5/include/asm-x86_64/div64.h
--- linux-2.5.74-bk4/include/asm-x86_64/div64.h	2003-07-02 13:54:30.000000000 -0700
+++ linux-2.5.74-bk5/include/asm-x86_64/div64.h	2003-07-07 04:57:20.000000000 -0700
@@ -1,14 +1 @@
-#ifndef __X86_64_DIV64
-#define __X86_64_DIV64
-
-/*
- * Hey, we're already 64-bit, no
- * need to play games..
- */
-#define do_div(n,base) ({ \
-	int __res; \
-	__res = ((unsigned long) (n)) % (unsigned) (base); \
-	(n) = ((unsigned long) (n)) / (unsigned) (base); \
-	__res; })
-
-#endif
+#include <asm-generic/div64.h>
diff -urN linux-2.5.74-bk4/include/linux/acct.h linux-2.5.74-bk5/include/linux/acct.h
--- linux-2.5.74-bk4/include/linux/acct.h	2003-07-02 13:42:41.000000000 -0700
+++ linux-2.5.74-bk5/include/linux/acct.h	2003-07-07 04:57:20.000000000 -0700
@@ -78,7 +78,7 @@
 #ifdef CONFIG_BSD_PROCESS_ACCT
 struct super_block;
 extern void acct_auto_close(struct super_block *sb);
-extern int acct_process(long exitcode);
+extern void acct_process(long exitcode);
 #else
 #define acct_auto_close(x)	do { } while (0)
 #define acct_process(x)		do { } while (0)
diff -urN linux-2.5.74-bk4/include/linux/compat_ioctl.h linux-2.5.74-bk5/include/linux/compat_ioctl.h
--- linux-2.5.74-bk4/include/linux/compat_ioctl.h	2003-07-02 13:56:43.000000000 -0700
+++ linux-2.5.74-bk5/include/linux/compat_ioctl.h	2003-07-07 04:57:20.000000000 -0700
@@ -117,7 +117,7 @@
 COMPATIBLE_IOCTL(STOP_ARRAY)
 COMPATIBLE_IOCTL(STOP_ARRAY_RO)
 COMPATIBLE_IOCTL(RESTART_ARRAY_RW)
-#ifdef CONFIG_DM
+#ifdef CONFIG_BLK_DEV_DM
 /* DM */
 COMPATIBLE_IOCTL(DM_VERSION)
 COMPATIBLE_IOCTL(DM_REMOVE_ALL)
diff -urN linux-2.5.74-bk4/include/linux/ext3_fs_i.h linux-2.5.74-bk5/include/linux/ext3_fs_i.h
--- linux-2.5.74-bk4/include/linux/ext3_fs_i.h	2003-07-02 13:40:12.000000000 -0700
+++ linux-2.5.74-bk5/include/linux/ext3_fs_i.h	2003-07-07 04:57:20.000000000 -0700
@@ -62,6 +62,16 @@
 	__u32	i_prealloc_count;
 #endif
 	__u32	i_dir_start_lookup;
+#ifdef CONFIG_EXT3_FS_XATTR
+	/*
+	 * Extended attributes can be read independently of the main file
+	 * data. Taking i_sem even when reading would cause contention
+	 * between readers of EAs and writers of regular file data, so
+	 * instead we synchronize on xattr_sem when reading or changing
+	 * EAs.
+	 */
+	struct rw_semaphore xattr_sem;
+#endif
 #ifdef CONFIG_EXT3_FS_POSIX_ACL
 	struct posix_acl	*i_acl;
 	struct posix_acl	*i_default_acl;
diff -urN linux-2.5.74-bk4/include/linux/fs.h linux-2.5.74-bk5/include/linux/fs.h
--- linux-2.5.74-bk4/include/linux/fs.h	2003-07-07 04:56:59.000000000 -0700
+++ linux-2.5.74-bk5/include/linux/fs.h	2003-07-07 04:57:20.000000000 -0700
@@ -420,6 +420,8 @@
 	unsigned long ahead_start;	/* Ahead window */
 	unsigned long ahead_size;
 	unsigned long ra_pages;		/* Maximum readahead window */
+	unsigned long mmap_hit;		/* Cache hit stat for mmap accesses */
+	unsigned long mmap_miss;	/* Cache miss stat for mmap accesses */
 };
 
 struct file {
diff -urN linux-2.5.74-bk4/include/linux/mm.h linux-2.5.74-bk5/include/linux/mm.h
--- linux-2.5.74-bk4/include/linux/mm.h	2003-07-07 04:56:59.000000000 -0700
+++ linux-2.5.74-bk5/include/linux/mm.h	2003-07-07 04:57:20.000000000 -0700
@@ -571,10 +571,6 @@
 			  struct file_ra_state *ra,
 			  struct file *filp,
 			  unsigned long offset);
-void page_cache_readaround(struct address_space *mapping, 
-			   struct file_ra_state *ra,
-			   struct file *filp,
-			   unsigned long offset);
 void handle_ra_miss(struct address_space *mapping, 
 		    struct file_ra_state *ra, pgoff_t offset);
 unsigned long max_sane_readahead(unsigned long nr);
diff -urN linux-2.5.74-bk4/include/linux/quota.h linux-2.5.74-bk5/include/linux/quota.h
--- linux-2.5.74-bk4/include/linux/quota.h	2003-07-02 13:51:56.000000000 -0700
+++ linux-2.5.74-bk5/include/linux/quota.h	2003-07-07 04:57:20.000000000 -0700
@@ -306,6 +306,16 @@
 void unregister_quota_format(struct quota_format_type *fmt);
 void init_dquot_operations(struct dquot_operations *fsdqops);
 
+struct quota_module_name {
+	int qm_fmt_id;
+	char *qm_mod_name;
+};
+
+#define INIT_QUOTA_MODULE_NAMES {\
+	{QFMT_VFS_OLD, "quota_v1"},\
+	{QFMT_VFS_V0, "quota_v2"},\
+	{0, NULL}}
+
 #else
 
 # /* nodep */ include <sys/cdefs.h>
diff -urN linux-2.5.74-bk4/kernel/acct.c linux-2.5.74-bk5/kernel/acct.c
--- linux-2.5.74-bk4/kernel/acct.c	2003-07-02 13:48:43.000000000 -0700
+++ linux-2.5.74-bk5/kernel/acct.c	2003-07-07 04:57:20.000000000 -0700
@@ -394,17 +394,26 @@
 /*
  * acct_process - now just a wrapper around do_acct_process
  */
-int acct_process(long exitcode)
+void acct_process(long exitcode)
 {
 	struct file *file = NULL;
+
+	/*
+	 * accelerate the common fastpath:
+	 */
+	if (!acct_globals.file)
+		return;
+
 	spin_lock(&acct_globals.lock);
-	if (acct_globals.file) {
-		file = acct_globals.file;
-		get_file(file);
-		spin_unlock(&acct_globals.lock);
-		do_acct_process(exitcode, file);
-		fput(file);
-	} else
-		spin_unlock(&acct_globals.lock);
-	return 0;
+	file = acct_globals.file;
+	if (!file)
+		goto out_unlock;
+
+	get_file(file);
+	spin_unlock(&acct_globals.lock);
+	do_acct_process(exitcode, file);
+	fput(file);
+
+out_unlock:
+	spin_unlock(&acct_globals.lock);
 }
diff -urN linux-2.5.74-bk4/kernel/sched.c linux-2.5.74-bk5/kernel/sched.c
--- linux-2.5.74-bk4/kernel/sched.c	2003-07-02 13:53:09.000000000 -0700
+++ linux-2.5.74-bk5/kernel/sched.c	2003-07-07 04:57:20.000000000 -0700
@@ -508,8 +508,8 @@
 		}
 #ifdef CONFIG_SMP
 	       	else
-			if (unlikely(kick) && task_running(rq, p) && (p->thread_info->cpu != smp_processor_id()))
-				smp_send_reschedule(p->thread_info->cpu);
+			if (unlikely(kick) && task_running(rq, p) && (task_cpu(p) != smp_processor_id()))
+				smp_send_reschedule(task_cpu(p));
 #endif
 		p->state = TASK_RUNNING;
 	}
@@ -1332,7 +1332,7 @@
 switch_tasks:
 	prefetch(next);
 	clear_tsk_need_resched(prev);
-	RCU_qsctr(prev->thread_info->cpu)++;
+	RCU_qsctr(task_cpu(prev))++;
 
 	if (likely(prev != next)) {
 		rq->nr_switches++;
diff -urN linux-2.5.74-bk4/kernel/timer.c linux-2.5.74-bk5/kernel/timer.c
--- linux-2.5.74-bk4/kernel/timer.c	2003-07-02 13:54:19.000000000 -0700
+++ linux-2.5.74-bk5/kernel/timer.c	2003-07-07 04:57:20.000000000 -0700
@@ -126,13 +126,17 @@
 		 * or you set a timer to go off in the past
 		 */
 		vec = base->tv1.vec + (base->timer_jiffies & TVR_MASK);
-	} else if (idx <= 0xffffffffUL) {
-		int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
-		vec = base->tv5.vec + i;
 	} else {
-		/* Can only get here on architectures with 64-bit jiffies */
-		INIT_LIST_HEAD(&timer->entry);
-		return;
+		int i;
+		/* If the timeout is larger than 0xffffffff on 64-bit
+		 * architectures then we use the maximum timeout:
+		 */
+		if (idx > 0xffffffffUL) {
+			idx = 0xffffffffUL;
+			expires = idx + base->timer_jiffies;
+		}
+		i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
+		vec = base->tv5.vec + i;
 	}
 	/*
 	 * Timers are FIFO:
diff -urN linux-2.5.74-bk4/lib/Makefile linux-2.5.74-bk5/lib/Makefile
--- linux-2.5.74-bk4/lib/Makefile	2003-07-02 13:40:29.000000000 -0700
+++ linux-2.5.74-bk5/lib/Makefile	2003-07-07 04:57:21.000000000 -0700
@@ -5,7 +5,7 @@
 
 lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
 	 bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
-	 kobject.o idr.o
+	 kobject.o idr.o div64.o
 
 lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
 lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
diff -urN linux-2.5.74-bk4/lib/div64.c linux-2.5.74-bk5/lib/div64.c
--- linux-2.5.74-bk4/lib/div64.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.5.74-bk5/lib/div64.c	2003-07-07 04:57:21.000000000 -0700
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2003 Bernardo Innocenti <bernie@develer.com>
+ *
+ * Based on former do_div() implementation from asm-parisc/div64.h:
+ *	Copyright (C) 1999 Hewlett-Packard Co
+ *	Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ *
+ * Generic C version of 64bit/32bit division and modulo, with
+ * 64bit result and 32bit remainder.
+ *
+ * The fast case for (n>>32 == 0) is handled inline by do_div(). 
+ *
+ * Code generated for this function might be very inefficient
+ * for some CPUs. div64_32() can be overridden by linking arch-specific
+ * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S.
+ */
+
+#include <linux/types.h>
+#include <asm/div64.h>
+
+uint32_t __div64_32(uint64_t *n, uint32_t base)
+{
+	uint32_t low, low2, high, rem;
+
+	low   = *n   & 0xffffffff;
+	high  = *n  >> 32;
+	rem   = high % (uint32_t)base;
+	high  = high / (uint32_t)base;
+	low2  = low >> 16;
+	low2 += rem << 16;
+	rem   = low2 % (uint32_t)base;
+	low2  = low2 / (uint32_t)base;
+	low   = low  & 0xffff;
+	low  += rem << 16;
+	rem   = low  % (uint32_t)base;
+	low   = low  / (uint32_t)base;
+
+	*n = low +
+		((uint64_t)low2 << 16) +
+		((uint64_t)high << 32);
+
+	return rem;
+}
+
diff -urN linux-2.5.74-bk4/mm/filemap.c linux-2.5.74-bk5/mm/filemap.c
--- linux-2.5.74-bk4/mm/filemap.c	2003-07-02 13:45:11.000000000 -0700
+++ linux-2.5.74-bk5/mm/filemap.c	2003-07-07 04:57:21.000000000 -0700
@@ -925,6 +925,9 @@
 	return error == -EEXIST ? 0 : error;
 }
 
+#define MMAP_READAROUND (16UL)
+#define MMAP_LOTSAMISS  (100)
+
 /*
  * filemap_nopage() is invoked via the vma operations vector for a
  * mapped memory region to read in file data during a page fault.
@@ -942,19 +945,19 @@
 	struct inode *inode = mapping->host;
 	struct page *page;
 	unsigned long size, pgoff, endoff;
-	int did_readahead;
+	int did_readaround = 0;
 
 	pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
 	endoff = ((area->vm_end - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
 
 retry_all:
-	/*
-	 * An external ptracer can access pages that normally aren't
-	 * accessible..
-	 */
 	size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-	if ((pgoff >= size) && (area->vm_mm == current->mm))
-		return NULL;
+	if (pgoff >= size)
+		goto outside_data_content;
+
+	/* If we don't want any read-ahead, don't bother */
+	if (VM_RandomReadHint(area))
+		goto no_cached_page;
 
 	/*
 	 * The "size" of the file, as far as mmap is concerned, isn't bigger
@@ -963,25 +966,14 @@
 	if (size > endoff)
 		size = endoff;
 
-	did_readahead = 0;
-
 	/*
 	 * The readahead code wants to be told about each and every page
 	 * so it can build and shrink its windows appropriately
+	 *
+	 * For sequential accesses, we use the generic readahead logic.
 	 */
-	if (VM_SequentialReadHint(area)) {
-		did_readahead = 1;
+	if (VM_SequentialReadHint(area))
 		page_cache_readahead(mapping, ra, file, pgoff);
-	}
-
-	/*
-	 * If the offset is outside the mapping size we're off the end
-	 * of a privately mapped file, so we need to map a zero page.
-	 */
-	if ((pgoff < size) && !VM_RandomReadHint(area)) {
-		did_readahead = 1;
-		page_cache_readaround(mapping, ra, file, pgoff);
-	}
 
 	/*
 	 * Do we have something in the page cache already?
@@ -989,13 +981,27 @@
 retry_find:
 	page = find_get_page(mapping, pgoff);
 	if (!page) {
-		if (did_readahead) {
+		if (VM_SequentialReadHint(area)) {
 			handle_ra_miss(mapping, ra, pgoff);
-			did_readahead = 0;
+			goto no_cached_page;
 		}
-		goto no_cached_page;
+		ra->mmap_miss++;
+
+		/*
+		 * Do we miss much more than hit in this file? If so,
+		 * stop bothering with read-ahead. It will only hurt.
+		 */
+		if (ra->mmap_miss > ra->mmap_hit + MMAP_LOTSAMISS)
+			goto no_cached_page;
+
+		did_readaround = 1;
+		do_page_cache_readahead(mapping, file, pgoff & ~(MMAP_READAROUND-1), MMAP_READAROUND);
+		goto retry_find;
 	}
 
+	if (!did_readaround)
+		ra->mmap_hit++;
+
 	/*
 	 * Ok, found a page in the page cache, now we need to check
 	 * that it's up-to-date.
@@ -1010,6 +1016,14 @@
 	mark_page_accessed(page);
 	return page;
 
+outside_data_content:
+	/*
+	 * An external ptracer can access pages that normally aren't
+	 * accessible..
+	 */
+	if (area->vm_mm == current->mm)
+		return NULL;
+	/* Fall through to the non-read-ahead case */
 no_cached_page:
 	/*
 	 * We're only likely to ever get here if MADV_RANDOM is in
diff -urN linux-2.5.74-bk4/mm/readahead.c linux-2.5.74-bk5/mm/readahead.c
--- linux-2.5.74-bk4/mm/readahead.c	2003-07-07 04:57:01.000000000 -0700
+++ linux-2.5.74-bk5/mm/readahead.c	2003-07-07 04:57:21.000000000 -0700
@@ -437,37 +437,6 @@
 	return;
 }
 
-/*
- * For mmap reads (typically executables) the access pattern is fairly random,
- * but somewhat ascending.  So readaround favours pages beyond the target one.
- * We also boost the window size, as it can easily shrink due to misses.
- */
-void
-page_cache_readaround(struct address_space *mapping, struct file_ra_state *ra,
-			struct file *filp, unsigned long offset)
-{
-	if (ra->next_size != -1UL) {
-		const unsigned long min = get_min_readahead(ra) * 4;
-		unsigned long target;
-		unsigned long backward;
-
-		/*
-		 * If next_size is zero then leave it alone, because that's a
-		 * readahead startup state.
-		 */
-		if (ra->next_size && ra->next_size < min)
-			ra->next_size = min;
-
-		target = offset;
-		backward = ra->next_size / 4;
-
-		if (backward > target)
-			target = 0;
-		else
-			target -= backward;
-		page_cache_readahead(mapping, ra, filp, target);
-	}
-}
 
 /*
  * handle_ra_miss() is called when it is known that a page which should have
diff -urN linux-2.5.74-bk4/net/ipv4/igmp.c linux-2.5.74-bk5/net/ipv4/igmp.c
--- linux-2.5.74-bk4/net/ipv4/igmp.c	2003-07-02 13:57:31.000000000 -0700
+++ linux-2.5.74-bk5/net/ipv4/igmp.c	2003-07-07 04:57:21.000000000 -0700
@@ -2099,7 +2099,7 @@
 	struct in_device *in_dev;
 };
 
-#define	igmp_mc_seq_private(seq)	((struct igmp_mc_iter_state *)&seq->private)
+#define	igmp_mc_seq_private(seq)	((struct igmp_mc_iter_state *)(seq)->private)
 
 static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq)
 {
@@ -2254,7 +2254,7 @@
 	struct ip_mc_list *im;
 };
 
-#define igmp_mcf_seq_private(seq)	((struct igmp_mcf_iter_state *)&seq->private)
+#define igmp_mcf_seq_private(seq)	((struct igmp_mcf_iter_state *)(seq)->private)
 
 static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq)
 {
diff -urN linux-2.5.74-bk4/net/ipv4/ipconfig.c linux-2.5.74-bk5/net/ipv4/ipconfig.c
--- linux-2.5.74-bk4/net/ipv4/ipconfig.c	2003-07-02 13:40:27.000000000 -0700
+++ linux-2.5.74-bk5/net/ipv4/ipconfig.c	2003-07-07 04:57:21.000000000 -0700
@@ -1115,6 +1115,8 @@
 				       "nameserver %u.%u.%u.%u\n",
 				       NIPQUAD(ic_nameservers[i]));
 	}
+	len += sprintf(buffer + len, "bootserver %u.%u.%u.%u\n",
+			NIPQUAD(ic_servaddr));
 
 	if (offset > len)
 		offset = len;
diff -urN linux-2.5.74-bk4/net/ipv4/raw.c linux-2.5.74-bk5/net/ipv4/raw.c
--- linux-2.5.74-bk4/net/ipv4/raw.c	2003-07-02 13:49:08.000000000 -0700
+++ linux-2.5.74-bk5/net/ipv4/raw.c	2003-07-07 04:57:21.000000000 -0700
@@ -687,7 +687,7 @@
 	int bucket;
 };
 
-#define raw_seq_private(seq) ((struct raw_iter_state *)&seq->private)
+#define raw_seq_private(seq) ((struct raw_iter_state *)(seq)->private)
 
 static struct sock *raw_get_first(struct seq_file *seq)
 {
diff -urN linux-2.5.74-bk4/net/ipv6/anycast.c linux-2.5.74-bk5/net/ipv6/anycast.c
--- linux-2.5.74-bk4/net/ipv6/anycast.c	2003-07-02 13:40:16.000000000 -0700
+++ linux-2.5.74-bk5/net/ipv6/anycast.c	2003-07-07 04:57:21.000000000 -0700
@@ -441,7 +441,7 @@
 	struct inet6_dev *idev;
 };
 
-#define ac6_seq_private(seq)	((struct ac6_iter_state *)&seq->private)
+#define ac6_seq_private(seq)	((struct ac6_iter_state *)(seq)->private)
 
 static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq)
 {
diff -urN linux-2.5.74-bk4/net/ipv6/ip6_flowlabel.c linux-2.5.74-bk5/net/ipv6/ip6_flowlabel.c
--- linux-2.5.74-bk4/net/ipv6/ip6_flowlabel.c	2003-07-02 13:43:27.000000000 -0700
+++ linux-2.5.74-bk5/net/ipv6/ip6_flowlabel.c	2003-07-07 04:57:21.000000000 -0700
@@ -559,7 +559,7 @@
 	int bucket;
 };
 
-#define ip6fl_seq_private(seq)	((struct ip6fl_iter_state *)&(seq)->private)
+#define ip6fl_seq_private(seq)	((struct ip6fl_iter_state *)(seq)->private)
 
 static struct ip6_flowlabel *ip6fl_get_first(struct seq_file *seq)
 {
diff -urN linux-2.5.74-bk4/net/ipv6/mcast.c linux-2.5.74-bk5/net/ipv6/mcast.c
--- linux-2.5.74-bk4/net/ipv6/mcast.c	2003-07-02 13:54:38.000000000 -0700
+++ linux-2.5.74-bk5/net/ipv6/mcast.c	2003-07-07 04:57:22.000000000 -0700
@@ -2045,7 +2045,7 @@
 	struct inet6_dev *idev;
 };
 
-#define igmp6_mc_seq_private(seq)	((struct igmp6_mc_iter_state *)&seq->private)
+#define igmp6_mc_seq_private(seq)	((struct igmp6_mc_iter_state *)(seq)->private)
 
 static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq)
 {
@@ -2185,7 +2185,7 @@
 	struct ifmcaddr6 *im;
 };
 
-#define igmp6_mcf_seq_private(seq)	((struct igmp6_mcf_iter_state *)&seq->private)
+#define igmp6_mcf_seq_private(seq)	((struct igmp6_mcf_iter_state *)(seq)->private)
 
 static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq)
 {
diff -urN linux-2.5.74-bk4/net/ipv6/raw.c linux-2.5.74-bk5/net/ipv6/raw.c
--- linux-2.5.74-bk4/net/ipv6/raw.c	2003-07-02 13:46:08.000000000 -0700
+++ linux-2.5.74-bk5/net/ipv6/raw.c	2003-07-07 04:57:22.000000000 -0700
@@ -913,7 +913,7 @@
 	int bucket;
 };
 
-#define raw6_seq_private(seq) ((struct raw6_iter_state *)&seq->private)
+#define raw6_seq_private(seq) ((struct raw6_iter_state *)(seq)->private)
 
 static struct sock *raw6_get_first(struct seq_file *seq)
 {
