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

diff -urN linux-2.4.23-bk5/Documentation/Changes linux-2.4.23-bk6/Documentation/Changes
--- linux-2.4.23-bk5/Documentation/Changes	2003-12-08 02:54:06.000000000 -0800
+++ linux-2.4.23-bk6/Documentation/Changes	2003-12-08 02:54:08.000000000 -0800
@@ -56,6 +56,7 @@
 o  e2fsprogs              1.25                    # tune2fs
 o  jfsutils               1.0.12                  # fsck.jfs -V
 o  reiserfsprogs          3.6.3                   # reiserfsck -V 2>&1|grep reiserfsprogs
+o  xfsprogs               2.6.0                   # xfs_db -V
 o  pcmcia-cs              3.1.21                  # cardmgr -V
 o  quota-tools            3.09                    # quota -V
 o  PPP                    2.4.0                   # pppd --version
@@ -191,6 +192,16 @@
 versions of mkreiserfs, resize_reiserfs, debugreiserfs and
 reiserfsck. These utils work on both i386 and alpha platforms.
 
+Xfsprogs
+--------
+
+The latest version of xfsprogs contains mkfs.xfs, xfs_db, and the
+xfs_repair utilities, among others, for the XFS filesystem.  It is
+architecture independent and any version from 2.0.0 onward should
+work correctly with this version of the XFS kernel code (2.6.0 or
+later is recommended, due to some significant improvements).
+
+
 Pcmcia-cs
 ---------
 
@@ -336,6 +347,10 @@
 -------------
 o  <http://www.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.6.3.tar.gz>
 
+Xfsprogs
+--------
+o  <ftp://oss.sgi.com/projects/xfs/download/>
+
 LVM toolset
 -----------
 o  <http://www.sistina.com/lvm/>
diff -urN linux-2.4.23-bk5/Documentation/Configure.help linux-2.4.23-bk6/Documentation/Configure.help
--- linux-2.4.23-bk5/Documentation/Configure.help	2003-12-08 02:54:06.000000000 -0800
+++ linux-2.4.23-bk6/Documentation/Configure.help	2003-12-08 02:54:08.000000000 -0800
@@ -17231,6 +17231,80 @@
   Say Y here if you want to try writing to UFS partitions. This is
   experimental, so you should back up your UFS partitions beforehand.
 
+XFS filesystem support
+CONFIG_XFS_FS
+  XFS is a high performance journaling filesystem which originated
+  on the SGI IRIX platform.  It is completely multi-threaded, can
+  support large files and large filesystems, extended attributes,
+  variable block sizes, is extent based, and makes extensive use of
+  Btrees (directories, extents, free space) to aid both performance
+  and scalability.
+
+  Refer to the documentation at <http://oss.sgi.com/projects/xfs/>
+  for complete details.  This implementation is on-disk compatible
+  with the IRIX version of XFS.
+
+  If you want to compile this file system as a module ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want), say M here and read <file:Documentation/modules.txt>.  The
+  module will be called xfs.o.  Be aware, however, that if the file
+  system of your root partition is compiled as a module, you'll need
+  to use an initial ramdisk (initrd) to boot.
+
+Quota support
+CONFIG_XFS_QUOTA
+  If you say Y here, you will be able to set limits for disk usage on
+  a per user and/or per group basis under XFS.  XFS considers quota
+  information as filesystem metadata and uses journaling to provide a
+  higher level guarantee of consistency.  The on-disk data format for
+  quota is also compatible with the IRIX version of XFS, allowing a
+  filesystem to be migrated between Linux and IRIX without any need
+  for conversion.
+
+  If unsure, say N.  More comprehensive documentation can be found in
+  README.quota in the xfsprogs package.  XFS quota can be used either
+  with or without the generic quota support enabled (CONFIG_QUOTA) -
+  they are completely independent subsystems.
+
+Realtime support (EXPERIMENTAL)
+CONFIG_XFS_RT
+  If you say Y here you will be able to mount and use XFS filesystems
+  which contain a realtime subvolume. The realtime subvolume is a
+  separate area of disk space where only file data is stored. The
+  realtime subvolume is designed to provide very deterministic
+  data rates suitable for media streaming applications.
+
+  See the xfs man page in section 5 for a bit more information.
+
+  This feature is unsupported at this time, is not yet fully
+  functional, and may cause serious problems.
+
+  If unsure, say N.
+
+Tracing support (EXPERIMENTAL)
+CONFIG_XFS_TRACE
+  Say Y here to get an XFS build with activity tracing enabled.
+  Enabling this option will attach historical information to XFS
+  inodes, pagebufs, certain locks, the log, the IO path, and a
+  few other key areas within XFS.  These traces can be examined
+  using a kernel debugger.
+
+  Note that for the pagebuf traces, you will also have to enable
+  the sysctl in /proc/sys/vm/pagebuf/debug for this to work.
+
+  Say N unless you are an XFS developer.
+
+Debugging support (EXPERIMENTAL)
+CONFIG_XFS_DEBUG
+  Say Y here to get an XFS build with many debugging features,
+  including ASSERT checks, function wrappers around macros,
+  and extra sanity-checking functions in various code paths.
+
+  Note that the resulting code will be HUGE and SLOW, and probably
+  not useful unless you are debugging a particular problem.
+
+  Say N unless you are an XFS developer, or play one on TV.
+
 Advanced partition selection
 CONFIG_PARTITION_ADVANCED
   Say Y here if you would like to use hard disks under Linux which
diff -urN linux-2.4.23-bk5/Documentation/filesystems/00-INDEX linux-2.4.23-bk6/Documentation/filesystems/00-INDEX
--- linux-2.4.23-bk5/Documentation/filesystems/00-INDEX	2002-11-28 15:53:08.000000000 -0800
+++ linux-2.4.23-bk6/Documentation/filesystems/00-INDEX	2003-12-08 02:54:08.000000000 -0800
@@ -48,3 +48,5 @@
 	- info on using the VFAT filesystem used in Windows NT and Windows 95
 vfs.txt
 	- Overview of the Virtual File System
+xfs.txt
+	- info and mount options for the XFS filesystem.
diff -urN linux-2.4.23-bk5/Documentation/filesystems/xfs.txt linux-2.4.23-bk6/Documentation/filesystems/xfs.txt
--- linux-2.4.23-bk5/Documentation/filesystems/xfs.txt	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.23-bk6/Documentation/filesystems/xfs.txt	2003-12-08 02:54:08.000000000 -0800
@@ -0,0 +1,203 @@
+
+The SGI XFS Filesystem
+======================
+
+XFS is a high performance journaling filesystem which originated
+on the SGI IRIX platform.  It is completely multi-threaded, can
+support large files and large filesystems, extended attributes,
+variable block sizes, is extent based, and makes extensive use of
+Btrees (directories, extents, free space) to aid both performance
+and scalability.
+
+Refer to the documentation at http://oss.sgi.com/projects/xfs/
+for further details.  This implementation is on-disk compatible
+with the IRIX version of XFS.
+
+
+Mount Options
+=============
+
+When mounting an XFS filesystem, the following options are accepted.
+
+  biosize=size
+	Sets the preferred buffered I/O size (default size is 64K).
+	"size" must be expressed as the logarithm (base2) of the
+	desired I/O size.
+	Valid values for this option are 14 through 16, inclusive
+	(i.e. 16K, 32K, and 64K bytes).  On machines with a 4K
+	pagesize, 13 (8K bytes) is also a valid size.
+	The preferred buffered I/O size can also be altered on an
+	individual file basis using the ioctl(2) system call.
+
+  ikeep/noikeep
+	When inode clusters are emptied of inodes, keep them around
+	on the disk (ikeep) - this is the traditional XFS behaviour
+	and is still the default for now.  Using the noikeep option,
+	inode clusters are returned to the free space pool.
+
+  logbufs=value
+	Set the number of in-memory log buffers.  Valid numbers range
+	from 2-8 inclusive.
+	The default value is 8 buffers for filesystems with a
+	blocksize of 64K, 4 buffers for filesystems with a blocksize
+	of 32K, 3 buffers for filesystems with a blocksize of 16K
+	and 2 buffers for all other configurations.  Increasing the
+	number of buffers may increase performance on some workloads
+	at the cost of the memory used for the additional log buffers
+	and their associated control structures.
+
+  logbsize=value
+	Set the size of each in-memory log buffer.
+	Size may be specified in bytes, or in kilobytes with a "k" suffix.
+	Valid sizes for version 1 and version 2 logs are 16384 (16k) and 
+	32768 (32k).  Valid sizes for version 2 logs also include 
+	65536 (64k), 131072 (128k) and 262144 (256k).
+	The default value for machines with more than 32MB of memory
+	is 32768, machines with less memory use 16384 by default.
+
+  logdev=device and rtdev=device
+	Use an external log (metadata journal) and/or real-time device.
+	An XFS filesystem has up to three parts: a data section, a log
+	section, and a real-time section.  The real-time section is
+	optional, and the log section can be separate from the data
+	section or contained within it.
+
+  noalign
+	Data allocations will not be aligned at stripe unit boundaries.
+
+  noatime
+	Access timestamps are not updated when a file is read.
+
+  norecovery
+	The filesystem will be mounted without running log recovery.
+	If the filesystem was not cleanly unmounted, it is likely to
+	be inconsistent when mounted in "norecovery" mode.
+	Some files or directories may not be accessible because of this.
+	Filesystems mounted "norecovery" must be mounted read-only or
+	the mount will fail.
+
+  nouuid
+	Don't check for double mounted file systems using the file system uuid.
+	This is useful to mount LVM snapshot volumes.
+
+  osyncisosync
+	Make O_SYNC writes implement true O_SYNC.  WITHOUT this option,
+	Linux XFS behaves as if an "osyncisdsync" option is used,
+	which will make writes to files opened with the O_SYNC flag set
+	behave as if the O_DSYNC flag had been used instead.
+	This can result in better performance without compromising
+	data safety.
+	However if this option is not in effect, timestamp updates from
+	O_SYNC writes can be lost if the system crashes.
+	If timestamp updates are critical, use the osyncisosync option.
+
+  quota/usrquota/uqnoenforce
+	User disk quota accounting enabled, and limits (optionally)
+	enforced.
+
+  grpquota/gqnoenforce
+	Group disk quota accounting enabled and limits (optionally)
+	enforced.
+
+  sunit=value and swidth=value
+	Used to specify the stripe unit and width for a RAID device or
+	a stripe volume.  "value" must be specified in 512-byte block
+	units.
+	If this option is not specified and the filesystem was made on
+	a stripe volume or the stripe width or unit were specified for
+	the RAID device at mkfs time, then the mount system call will
+	restore the value from the superblock.  For filesystems that
+	are made directly on RAID devices, these options can be used
+	to override the information in the superblock if the underlying
+	disk layout changes after the filesystem has been created.
+	The "swidth" option is required if the "sunit" option has been
+	specified, and must be a multiple of the "sunit" value.
+
+sysctls
+=======
+
+The following sysctls are available for the XFS filesystem:
+
+  fs.xfs.stats_clear		(Min: 0  Default: 0  Max: 1)
+	Setting this to "1" clears accumulated XFS statistics 
+	in /proc/fs/xfs/stat.  It then immediately reset to "0".
+  	
+  fs.xfs.sync_interval		(Min: HZ  Default: 30*HZ  Max: 60*HZ)
+	The interval at which the xfssyncd thread for xfs filesystems
+	flushes metadata out to disk. This thread will flush log
+	activity out, and do some processing on unlinked inodes
+
+  fs.xfs.error_level		(Min: 0  Default: 3  Max: 11)
+	A volume knob for error reporting when internal errors occur.
+	This will generate detailed messages & backtraces for filesystem
+	shutdowns, for example.  Current threshold values are:
+
+		XFS_ERRLEVEL_OFF:       0
+		XFS_ERRLEVEL_LOW:       1
+		XFS_ERRLEVEL_HIGH:      5
+
+  fs.xfs.panic_mask		(Min: 0  Default: 0  Max: 127)
+	Causes certain error conditions to call BUG(). Value is a bitmask; 
+	AND together the tags which represent errors which should cause panics:
+	
+		XFS_NO_PTAG                     0
+		XFS_PTAG_IFLUSH                 0x00000001
+		XFS_PTAG_LOGRES                 0x00000002
+		XFS_PTAG_AILDELETE              0x00000004
+		XFS_PTAG_ERROR_REPORT           0x00000008
+		XFS_PTAG_SHUTDOWN_CORRUPT       0x00000010
+		XFS_PTAG_SHUTDOWN_IOERROR       0x00000020
+		XFS_PTAG_SHUTDOWN_LOGERROR      0x00000040
+
+	This option is intended for debugging only.		
+
+  fs.xfs.irix_symlink_mode	(Min: 0  Default: 0  Max: 1)
+	Controls whether symlinks are created with mode 0777 (default)
+	or whether their mode is affected by the umask (irix mode).
+
+  fs.xfs.irix_sgid_inherit	(Min: 0  Default: 0  Max: 1)
+	Controls files created in SGID directories.
+	If the group ID of the new file does not match the effective group
+	ID or one of the supplementary group IDs of the parent dir, the 
+	ISGID bit is cleared if the irix_sgid_inherit compatibility sysctl 
+	is set.
+
+  fs.xfs.restrict_chown		(Min: 0  Default: 1  Max: 1)
+  	Controls whether unprivileged users can use chown to "give away"
+	a file to another user.
+
+  fs.xfs.refcache_size		(Min: 0  Default: 128  Max: 512)
+	Controls the size of the NFS refcache, which holds references
+	on files opened via NFS to improve performance.  The value
+	is the maximum number of files which can be in the cache at
+	any one time.
+
+  fs.xfs.refcache_purge		(Min: 0  Default: 32  Max: 512)
+	Controls the number of entries purged from the NFS refcache
+	every sync interval.
+
+  fs.xfs.inherit_sync		(Min: 0  Default: 1  Max 1)
+	Setting this to "1" will cause the "sync" flag set 
+	by the chattr(1) command on a directory to be
+	inherited by files in that directory.
+
+  fs.xfs.inherit_nodump		(Min: 0  Default: 1  Max 1)
+	Setting this to "1" will cause the "nodump" flag set 
+	by the chattr(1) command on a directory to be
+	inherited by files in that directory.
+
+  fs.xfs.inherit_noatime	(Min: 0  Default: 1  Max 1)
+	Setting this to "1" will cause the "noatime" flag set 
+	by the chattr(1) command on a directory to be
+	inherited by files in that directory.
+
+  vm.pagebuf.stats_clear	(Min: 0  Default: 0  Max: 1)
+	Setting this to "1" clears accumulated pagebuf statistics 
+	in /proc/fs/pagebuf/stat.  It then immediately reset to "0".
+  	
+  vm.pagebuf.flush_age		(Min: 1*HZ  Default: 15*HZ  Max: 300*HZ)
+	The age at which dirty metadata buffers are flushed to disk
+
+  vm.pagebuf.flush_int		(Min: HZ/2  Default: HZ  Max: 30*HZ)
+	The interval at which the list of dirty metadata buffers is
+	scanned.
diff -urN linux-2.4.23-bk5/MAINTAINERS linux-2.4.23-bk6/MAINTAINERS
--- linux-2.4.23-bk5/MAINTAINERS	2003-12-08 02:54:06.000000000 -0800
+++ linux-2.4.23-bk6/MAINTAINERS	2003-12-08 02:54:08.000000000 -0800
@@ -2130,6 +2130,14 @@
 L:	linux-x25@vger.kernel.org
 S:	Maintained
 
+XFS FILESYSTEM
+P:	Silicon Graphics Inc
+M:	owner-xfs@oss.sgi.com
+M:	nathans@sgi.com
+L:	linux-xfs@oss.sgi.com
+W:	http://oss.sgi.com/projects/xfs
+S:	Supported
+
 X86 3-LEVEL PAGING (PAE) SUPPORT
 P:	Ingo Molnar
 M:	mingo@redhat.com
diff -urN linux-2.4.23-bk5/Makefile linux-2.4.23-bk6/Makefile
--- linux-2.4.23-bk5/Makefile	2003-12-08 02:54:06.000000000 -0800
+++ linux-2.4.23-bk6/Makefile	2003-12-08 02:54:08.000000000 -0800
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 23
-EXTRAVERSION = -bk5
+EXTRAVERSION = -bk6
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.23-bk5/drivers/block/ll_rw_blk.c linux-2.4.23-bk6/drivers/block/ll_rw_blk.c
--- linux-2.4.23-bk5/drivers/block/ll_rw_blk.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.23-bk6/drivers/block/ll_rw_blk.c	2003-12-08 02:54:09.000000000 -0800
@@ -1377,9 +1377,7 @@
 	for (i = 0; i < nr; i++) {
 		struct buffer_head *bh = bhs[i];
 
-		/* Only one thread can actually submit the I/O. */
-		if (test_and_set_bit(BH_Lock, &bh->b_state))
-			continue;
+		lock_buffer(bh);
 
 		/* We have the buffer lock */
 		atomic_inc(&bh->b_count);
diff -urN linux-2.4.23-bk5/fs/Config.in linux-2.4.23-bk6/fs/Config.in
--- linux-2.4.23-bk5/fs/Config.in	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk6/fs/Config.in	2003-12-08 02:54:10.000000000 -0800
@@ -101,6 +101,12 @@
 tristate 'UFS file system support (read only)' CONFIG_UFS_FS
 dep_mbool '  UFS file system write support (DANGEROUS)' CONFIG_UFS_FS_WRITE $CONFIG_UFS_FS $CONFIG_EXPERIMENTAL
 
+tristate 'XFS filesystem support' CONFIG_XFS_FS
+dep_mbool    '  Quota support' CONFIG_XFS_QUOTA $CONFIG_XFS_FS
+dep_mbool    '  Realtime support (EXPERIMENTAL)' CONFIG_XFS_RT $CONFIG_XFS_FS $CONFIG_EXPERIMENTAL
+dep_mbool    '  Tracing support (EXPERIMENTAL)' CONFIG_XFS_TRACE $CONFIG_XFS_FS $CONFIG_EXPERIMENTAL
+dep_mbool    '  Debugging support (EXPERIMENTAL)' CONFIG_XFS_DEBUG $CONFIG_XFS_FS $CONFIG_EXPERIMENTAL
+
 if [ "$CONFIG_NET" = "y" ]; then
 
    mainmenu_option next_comment
diff -urN linux-2.4.23-bk5/fs/Makefile linux-2.4.23-bk6/fs/Makefile
--- linux-2.4.23-bk5/fs/Makefile	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.23-bk6/fs/Makefile	2003-12-08 02:54:10.000000000 -0800
@@ -8,7 +8,7 @@
 O_TARGET := fs.o
 
 export-objs :=	filesystems.o open.o dcache.o buffer.o dquot.o
-mod-subdirs :=	nls
+mod-subdirs :=	nls xfs
 
 obj-y :=	open.o read_write.o devices.o file_table.o buffer.o \
 		super.o block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \
@@ -66,7 +66,7 @@
 subdir-$(CONFIG_SUN_OPENPROMFS)	+= openpromfs
 subdir-$(CONFIG_BEFS_FS)	+= befs
 subdir-$(CONFIG_JFS_FS)		+= jfs
-
+subdir-$(CONFIG_XFS_FS)		+= xfs
 
 obj-$(CONFIG_BINFMT_AOUT)	+= binfmt_aout.o
 obj-$(CONFIG_BINFMT_EM86)	+= binfmt_em86.o
diff -urN linux-2.4.23-bk5/fs/buffer.c linux-2.4.23-bk6/fs/buffer.c
--- linux-2.4.23-bk5/fs/buffer.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk6/fs/buffer.c	2003-12-08 02:54:10.000000000 -0800
@@ -130,6 +130,36 @@
 int bdflush_min[N_PARAM] = {  0,  1,    0,   0,  0,   1*HZ,   0, 0, 0};
 int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,10000*HZ, 10000*HZ, 100, 100, 0};
 
+static inline int write_buffer_delay(struct buffer_head *bh)
+{
+	struct page *page = bh->b_page;
+
+	if (!TryLockPage(page)) {
+		spin_unlock(&lru_list_lock);
+		unlock_buffer(bh);
+		page->mapping->a_ops->writepage(page);
+		return 1;
+	}
+
+	return 0;
+}
+
+static inline void write_buffer(struct buffer_head *bh)
+{
+	if (buffer_delay(bh)) {
+		struct page *page = bh->b_page;
+
+		lock_page(page);
+		if (buffer_delay(bh)) {
+			page->mapping->a_ops->writepage(page);
+			return;
+		}
+		unlock_page(page);
+	}
+
+	ll_rw_block(WRITE, 1, &bh);
+}
+
 void unlock_buffer(struct buffer_head *bh)
 {
 	clear_bit(BH_Wait_IO, &bh->b_state);
@@ -233,7 +263,13 @@
 			continue;
 		if (test_and_set_bit(BH_Lock, &bh->b_state))
 			continue;
-		if (atomic_set_buffer_clean(bh)) {
+		if (buffer_delay(bh)) {
+			if (write_buffer_delay(bh)) {
+				if (count)
+					write_locked_buffers(array, count);
+				return -EAGAIN;
+			}
+		} else if (atomic_set_buffer_clean(bh)) {
 			__refile_buffer(bh);
 			get_bh(bh);
 			array[count++] = bh;
@@ -765,7 +801,7 @@
 	bh->b_private = private;
 }
 
-static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
+void end_buffer_io_async(struct buffer_head * bh, int uptodate)
 {
 	static spinlock_t page_uptodate_lock = SPIN_LOCK_UNLOCKED;
 	unsigned long flags;
@@ -880,7 +916,7 @@
 			 * a noop)
 			 */
 				wait_on_buffer(bh);
-				ll_rw_block(WRITE, 1, &bh);
+				write_buffer(bh);
 				brelse(bh);
 				spin_lock(&lru_list_lock);
 			}
@@ -1336,13 +1372,14 @@
  */
 static void discard_buffer(struct buffer_head * bh)
 {
-	if (buffer_mapped(bh)) {
+	if (buffer_mapped(bh) || buffer_delay(bh)) {
 		mark_buffer_clean(bh);
 		lock_buffer(bh);
 		clear_bit(BH_Uptodate, &bh->b_state);
 		clear_bit(BH_Mapped, &bh->b_state);
 		clear_bit(BH_Req, &bh->b_state);
 		clear_bit(BH_New, &bh->b_state);
+		clear_bit(BH_Delay, &bh->b_state);
 		remove_from_queues(bh);
 		unlock_buffer(bh);
 	}
@@ -1634,7 +1671,7 @@
 			set_bit(BH_Uptodate, &bh->b_state);
 			continue; 
 		}
-		if (!buffer_uptodate(bh) &&
+		if (!buffer_uptodate(bh) && !buffer_delay(bh) &&
 		     (block_start < from || block_end > to)) {
 			ll_rw_block(READ, 1, &bh);
 			*wait_bh++=bh;
@@ -2032,7 +2069,7 @@
 	if (Page_Uptodate(page))
 		set_bit(BH_Uptodate, &bh->b_state);
 
-	if (!buffer_uptodate(bh)) {
+	if (!buffer_uptodate(bh) && !buffer_delay(bh)) {
 		err = -EIO;
 		ll_rw_block(READ, 1, &bh);
 		wait_on_buffer(bh);
@@ -2226,8 +2263,8 @@
 	mark_buffer_uptodate(bh, uptodate);
 
 	kiobuf = bh->b_private;
-	unlock_buffer(bh);
 	end_kio_request(kiobuf, uptodate);
+	unlock_buffer(bh);
 }
 
 /*
@@ -2761,7 +2798,7 @@
 {
 #ifdef CONFIG_SMP
 	struct buffer_head * bh;
-	int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0;
+	int delalloc = 0, found = 0, locked = 0, dirty = 0, used = 0, lastused = 0;
 	int nlist;
 	static char *buf_types[NR_LIST] = { "CLEAN", "LOCKED", "DIRTY", };
 #endif
@@ -2776,7 +2813,7 @@
 	if (!spin_trylock(&lru_list_lock))
 		return;
 	for(nlist = 0; nlist < NR_LIST; nlist++) {
-		found = locked = dirty = used = lastused = 0;
+		delalloc = found = locked = dirty = used = lastused = 0;
 		bh = lru_list[nlist];
 		if(!bh) continue;
 
@@ -2786,6 +2823,8 @@
 				locked++;
 			if (buffer_dirty(bh))
 				dirty++;
+			if (buffer_delay(bh))
+				delalloc++;
 			if (atomic_read(&bh->b_count))
 				used++, lastused = found;
 			bh = bh->b_next_free;
@@ -2797,9 +2836,9 @@
 				       buf_types[nlist], found, tmp);
 		}
 		printk("%9s: %d buffers, %lu kbyte, %d used (last=%d), "
-		       "%d locked, %d dirty\n",
+		       "%d locked, %d dirty %d delay\n",
 		       buf_types[nlist], found, size_buffers_type[nlist]>>10,
-		       used, lastused, locked, dirty);
+		       used, lastused, locked, dirty, delalloc);
 	}
 	spin_unlock(&lru_list_lock);
 #endif
diff -urN linux-2.4.23-bk5/fs/exec.c linux-2.4.23-bk6/fs/exec.c
--- linux-2.4.23-bk5/fs/exec.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk6/fs/exec.c	2003-12-08 02:54:10.000000000 -0800
@@ -427,6 +427,15 @@
 
 	old_mm = current->mm;
 
+	if (old_mm && atomic_read(&old_mm->mm_users) == 1) {
+		mm_release();
+		down_write(&old_mm->mmap_sem);
+		exit_mmap(old_mm);
+		up_write(&old_mm->mmap_sem);
+		return 0;
+	}
+
+
 	mm = mm_alloc();
 	if (mm) {
 		struct mm_struct *active_mm;
diff -urN linux-2.4.23-bk5/fs/inode.c linux-2.4.23-bk6/fs/inode.c
--- linux-2.4.23-bk5/fs/inode.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk6/fs/inode.c	2003-12-08 02:54:10.000000000 -0800
@@ -140,6 +140,11 @@
 void inode_init_once(struct inode *inode)
 {
 	memset(inode, 0, sizeof(*inode));
+	__inode_init_once(inode);
+}
+
+void __inode_init_once(struct inode *inode)
+{
 	init_waitqueue_head(&inode->i_wait);
 	INIT_LIST_HEAD(&inode->i_hash);
 	INIT_LIST_HEAD(&inode->i_data.clean_pages);
@@ -878,6 +883,20 @@
 	return inode;
 }
 
+void unlock_new_inode(struct inode *inode)
+{
+	/*
+	 * This is special!  We do not need the spinlock
+	 * when clearing I_LOCK, because we're guaranteed
+	 * that nobody else tries to do anything about the
+	 * state of the inode when it is locked, as we
+	 * just created it (so there can be no old holders
+	 * that haven't tested I_LOCK).
+	 */
+	inode->i_state &= ~(I_LOCK|I_NEW);
+	wake_up(&inode->i_wait);
+}
+
 /*
  * This is called without the inode lock held.. Be careful.
  *
@@ -900,31 +919,13 @@
 			list_add(&inode->i_list, &inode_in_use);
 			list_add(&inode->i_hash, head);
 			inode->i_ino = ino;
-			inode->i_state = I_LOCK;
+			inode->i_state = I_LOCK|I_NEW;
 			spin_unlock(&inode_lock);
 
-			/* reiserfs specific hack right here.  We don't
-			** want this to last, and are looking for VFS changes
-			** that will allow us to get rid of it.
-			** -- mason@suse.com 
-			*/
-			if (sb->s_op->read_inode2) {
-				sb->s_op->read_inode2(inode, opaque) ;
-			} else {
-				sb->s_op->read_inode(inode);
-			}
-
 			/*
-			 * This is special!  We do not need the spinlock
-			 * when clearing I_LOCK, because we're guaranteed
-			 * that nobody else tries to do anything about the
-			 * state of the inode when it is locked, as we
-			 * just created it (so there can be no old holders
-			 * that haven't tested I_LOCK).
+			 * Return the locked inode with I_NEW set, the
+			 * caller is responsible for filling in the contents
 			 */
-			inode->i_state &= ~I_LOCK;
-			wake_up(&inode->i_wait);
-
 			return inode;
 		}
 
@@ -1035,8 +1036,7 @@
 	return inode;
 }
 
-
-struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
+struct inode *iget4_locked(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
 {
 	struct list_head * head = inode_hashtable + hash(sb,ino);
 	struct inode * inode;
diff -urN linux-2.4.23-bk5/fs/locks.c linux-2.4.23-bk6/fs/locks.c
--- linux-2.4.23-bk5/fs/locks.c	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.23-bk6/fs/locks.c	2003-12-08 02:54:10.000000000 -0800
@@ -135,15 +135,9 @@
 static kmem_cache_t *filelock_cache;
 
 /* Allocate an empty lock structure. */
-static struct file_lock *locks_alloc_lock(int account)
+static struct file_lock *locks_alloc_lock(void)
 {
-	struct file_lock *fl;
-	if (account && current->locks >= current->rlim[RLIMIT_LOCKS].rlim_cur)
-		return NULL;
-	fl = kmem_cache_alloc(filelock_cache, SLAB_KERNEL);
-	if (fl)
-		current->locks++;
-	return fl;
+	return kmem_cache_alloc(filelock_cache, SLAB_KERNEL);
 }
 
 /* Free a lock which is not in use. */
@@ -153,7 +147,6 @@
 		BUG();
 		return;
 	}
-	current->locks--;
 	if (waitqueue_active(&fl->fl_wait))
 		panic("Attempting to free lock with active wait queue");
 
@@ -220,7 +213,7 @@
 /* Fill in a file_lock structure with an appropriate FLOCK lock. */
 static struct file_lock *flock_make_lock(struct file *filp, unsigned int type)
 {
-	struct file_lock *fl = locks_alloc_lock(1);
+	struct file_lock *fl = locks_alloc_lock();
 	if (fl == NULL)
 		return NULL;
 
@@ -358,7 +351,7 @@
 /* Allocate a file_lock initialised to this type of lease */
 static int lease_alloc(struct file *filp, int type, struct file_lock **flp)
 {
-	struct file_lock *fl = locks_alloc_lock(1);
+	struct file_lock *fl = locks_alloc_lock();
 	if (fl == NULL)
 		return -ENOMEM;
 
@@ -721,7 +714,7 @@
 			 size_t count)
 {
 	struct file_lock *fl;
-	struct file_lock *new_fl = locks_alloc_lock(0);
+	struct file_lock *new_fl = locks_alloc_lock();
 	int error;
 
 	if (new_fl == NULL)
@@ -881,8 +874,8 @@
 	 * We may need two file_lock structures for this operation,
 	 * so we get them in advance to avoid races.
 	 */
-	new_fl = locks_alloc_lock(0);
-	new_fl2 = locks_alloc_lock(0);
+	new_fl = locks_alloc_lock();
+	new_fl2 = locks_alloc_lock();
 	error = -ENOLCK; /* "no luck" */
 	if (!(new_fl && new_fl2))
 		goto out_nolock;
@@ -1488,7 +1481,7 @@
 int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
 {
 	struct file *filp;
-	struct file_lock *file_lock = locks_alloc_lock(0);
+	struct file_lock *file_lock = locks_alloc_lock();
 	struct flock flock;
 	struct inode *inode;
 	int error;
@@ -1644,7 +1637,7 @@
 int fcntl_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l)
 {
 	struct file *filp;
-	struct file_lock *file_lock = locks_alloc_lock(0);
+	struct file_lock *file_lock = locks_alloc_lock();
 	struct flock64 flock;
 	struct inode *inode;
 	int error;
diff -urN linux-2.4.23-bk5/fs/open.c linux-2.4.23-bk6/fs/open.c
--- linux-2.4.23-bk5/fs/open.c	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.23-bk6/fs/open.c	2003-12-08 02:54:10.000000000 -0800
@@ -274,6 +274,9 @@
 	/* Don't worry, the checks are done in inode_change_ok() */
 	newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
 	if (times) {
+		error = -EPERM;
+		if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+			goto dput_and_out;
 		error = get_user(newattrs.ia_atime, &times->actime);
 		if (!error) 
 			error = get_user(newattrs.ia_mtime, &times->modtime);
@@ -282,6 +285,9 @@
 
 		newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
 	} else {
+		error = -EACCES;
+		if (IS_IMMUTABLE(inode))
+			goto dput_and_out;
 		if (current->fsuid != inode->i_uid &&
 		    (error = permission(inode,MAY_WRITE)) != 0)
 			goto dput_and_out;
@@ -320,6 +326,9 @@
 	newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
 	if (utimes) {
 		struct timeval times[2];
+		error = -EPERM;
+		if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+			goto dput_and_out;
 		error = -EFAULT;
 		if (copy_from_user(&times, utimes, sizeof(times)))
 			goto dput_and_out;
@@ -327,6 +336,10 @@
 		newattrs.ia_mtime = times[1].tv_sec;
 		newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
 	} else {
+		error = -EACCES;
+		if (IS_IMMUTABLE(inode))
+			goto dput_and_out;
+
 		if (current->fsuid != inode->i_uid &&
 		    (error = permission(inode,MAY_WRITE)) != 0)
 			goto dput_and_out;
diff -urN linux-2.4.23-bk5/include/linux/dqblk_xfs.h linux-2.4.23-bk6/include/linux/dqblk_xfs.h
--- linux-2.4.23-bk5/include/linux/dqblk_xfs.h	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.23-bk6/include/linux/dqblk_xfs.h	2003-12-08 02:54:10.000000000 -0800
@@ -105,15 +105,6 @@
 #define FS_DQ_TIMER_MASK	(FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER)
 
 /*
- * The following constants define the default amount of time given a user
- * before the soft limits are treated as hard limits (usually resulting
- * in an allocation failure).  These may be modified by the quotactl(2)
- * system call with the Q_XSETQLIM command.
- */
-#define	DQ_FTIMELIMIT	(7 * 24*60*60)		/* 1 week */
-#define	DQ_BTIMELIMIT	(7 * 24*60*60)		/* 1 week */
-
-/*
  * Various flags related to quotactl(2).  Only relevant to XFS filesystems.
  */
 #define XFS_QUOTA_UDQ_ACCT	(1<<0)  /* user quota accounting */
diff -urN linux-2.4.23-bk5/include/linux/fs.h linux-2.4.23-bk6/include/linux/fs.h
--- linux-2.4.23-bk5/include/linux/fs.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk6/include/linux/fs.h	2003-12-08 02:54:10.000000000 -0800
@@ -223,6 +223,7 @@
 	BH_Attached,	/* 1 if b_inode_buffers is linked into a list */
 	BH_JBD,		/* 1 if it has an attached journal_head */
 	BH_Sync,	/* 1 if the buffer is a sync read */
+	BH_Delay,       /* 1 if the buffer is delayed allocate */
 
 	BH_PrivateStart,/* not a state bit, but the first bit available
 			 * for private allocation by other entities
@@ -285,6 +286,7 @@
 #define buffer_new(bh)		__buffer_state(bh,New)
 #define buffer_async(bh)	__buffer_state(bh,Async)
 #define buffer_launder(bh)	__buffer_state(bh,Launder)
+#define buffer_delay(bh)	__buffer_state(bh,Delay)
 
 #define bh_offset(bh)		((unsigned long)(bh)->b_data & ~PAGE_MASK)
 
@@ -967,6 +969,7 @@
 #define I_LOCK			8
 #define I_FREEING		16
 #define I_CLEAR			32
+#define I_NEW			64
 
 #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
 
@@ -1145,6 +1148,7 @@
 extern void refile_buffer(struct buffer_head * buf);
 extern void create_empty_buffers(struct page *, kdev_t, unsigned long);
 extern void end_buffer_io_sync(struct buffer_head *bh, int uptodate);
+extern void end_buffer_io_async(struct buffer_head *bh, int uptodate);
 
 /* reiserfs_writepage needs this */
 extern void set_buffer_async_io(struct buffer_head *bh) ;
@@ -1287,6 +1291,7 @@
 }
 extern int inode_has_buffers(struct inode *);
 extern int do_fdatasync(struct file *);
+extern int filemap_fdatawrite(struct address_space *);
 extern int filemap_fdatasync(struct address_space *);
 extern int filemap_fdatawait(struct address_space *);
 extern void sync_supers(kdev_t dev, int wait);
@@ -1392,17 +1397,53 @@
 #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
 
 extern void inode_init_once(struct inode *);
+extern void __inode_init_once(struct inode *);
 extern void iput(struct inode *);
 extern void force_delete(struct inode *);
 extern struct inode * igrab(struct inode *);
 extern struct inode * ilookup(struct super_block *, unsigned long);
 extern ino_t iunique(struct super_block *, ino_t);
+extern void unlock_new_inode(struct inode *);
 
 typedef int (*find_inode_t)(struct inode *, unsigned long, void *);
-extern struct inode * iget4(struct super_block *, unsigned long, find_inode_t, void *);
+
+extern struct inode * iget4_locked(struct super_block *, unsigned long,
+				   find_inode_t, void *);
+
+static inline struct inode *iget4(struct super_block *sb, unsigned long ino,
+				  find_inode_t find_actor, void *opaque)
+{
+	struct inode *inode = iget4_locked(sb, ino, find_actor, opaque);
+
+	if (inode && (inode->i_state & I_NEW)) {
+		/*
+		 * reiserfs-specific kludge that is expected to go away ASAP.
+		 */
+		if (sb->s_op->read_inode2)
+			sb->s_op->read_inode2(inode, opaque);
+		else
+			sb->s_op->read_inode(inode);
+		unlock_new_inode(inode);
+	}
+
+	return inode;
+}
+
 static inline struct inode *iget(struct super_block *sb, unsigned long ino)
 {
-	return iget4(sb, ino, NULL, NULL);
+	struct inode *inode = iget4_locked(sb, ino, NULL, NULL);
+
+	if (inode && (inode->i_state & I_NEW)) {
+		sb->s_op->read_inode(inode);
+		unlock_new_inode(inode);
+	}
+
+	return inode;
+}
+
+static inline struct inode *iget_locked(struct super_block *sb, unsigned long ino)
+{
+	return iget4_locked(sb, ino, NULL, NULL);
 }
 
 extern void clear_inode(struct inode *);
@@ -1481,9 +1522,12 @@
 extern int generic_file_mmap(struct file *, struct vm_area_struct *);
 extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
 extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
+extern inline ssize_t do_generic_direct_read(struct file *, char *, size_t, loff_t *);
 extern int precheck_file_write(struct file *, struct inode *, size_t *, loff_t *);
 extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *);
 extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t);
+extern ssize_t do_generic_file_write(struct file *, const char *, size_t, loff_t *);
+extern ssize_t do_generic_direct_write(struct file *, const char *, size_t, loff_t *);
 extern loff_t no_llseek(struct file *file, loff_t offset, int origin);
 extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin);
 extern ssize_t generic_read_dir(struct file *, char *, size_t, loff_t *);
diff -urN linux-2.4.23-bk5/include/linux/sched.h linux-2.4.23-bk6/include/linux/sched.h
--- linux-2.4.23-bk5/include/linux/sched.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk6/include/linux/sched.h	2003-12-08 02:54:10.000000000 -0800
@@ -431,6 +431,7 @@
 #define PF_MEMALLOC	0x00000800	/* Allocating memory */
 #define PF_FREE_PAGES	0x00002000	/* per process page freeing */
 #define PF_NOIO		0x00004000	/* avoid generating further I/O */
+#define PF_FSTRANS	0x00008000	/* inside a filesystem transaction */
 
 #define PF_USEDFPU	0x00100000	/* task used FPU this quantum (SMP) */
 
diff -urN linux-2.4.23-bk5/kernel/ksyms.c linux-2.4.23-bk6/kernel/ksyms.c
--- linux-2.4.23-bk5/kernel/ksyms.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk6/kernel/ksyms.c	2003-12-08 02:54:10.000000000 -0800
@@ -145,15 +145,18 @@
 EXPORT_SYMBOL(igrab);
 EXPORT_SYMBOL(iunique);
 EXPORT_SYMBOL(ilookup);
-EXPORT_SYMBOL(iget4);
+EXPORT_SYMBOL(iget4_locked);
+EXPORT_SYMBOL(unlock_new_inode);
 EXPORT_SYMBOL(iput);
 EXPORT_SYMBOL(inode_init_once);
+EXPORT_SYMBOL(__inode_init_once);
 EXPORT_SYMBOL(force_delete);
 EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(follow_down);
 EXPORT_SYMBOL(lookup_mnt);
 EXPORT_SYMBOL(path_init);
 EXPORT_SYMBOL(path_walk);
+EXPORT_SYMBOL(path_lookup);
 EXPORT_SYMBOL(path_release);
 EXPORT_SYMBOL(__user_walk);
 EXPORT_SYMBOL(lookup_one_len);
@@ -173,6 +176,7 @@
 EXPORT_SYMBOL(__d_path);
 EXPORT_SYMBOL(mark_buffer_dirty);
 EXPORT_SYMBOL(set_buffer_async_io); /* for reiserfs_writepage */
+EXPORT_SYMBOL(end_buffer_io_async);
 EXPORT_SYMBOL(__mark_buffer_dirty);
 EXPORT_SYMBOL(__mark_inode_dirty);
 EXPORT_SYMBOL(fd_install);
@@ -226,6 +230,9 @@
 EXPORT_SYMBOL(generic_block_bmap);
 EXPORT_SYMBOL(generic_file_read);
 EXPORT_SYMBOL(do_generic_file_read);
+EXPORT_SYMBOL(do_generic_file_write);
+EXPORT_SYMBOL(do_generic_direct_read);
+EXPORT_SYMBOL(do_generic_direct_write);
 EXPORT_SYMBOL(generic_file_write);
 EXPORT_SYMBOL(generic_file_mmap);
 EXPORT_SYMBOL(generic_ro_fops);
@@ -251,6 +258,7 @@
 EXPORT_SYMBOL(find_inode_number);
 EXPORT_SYMBOL(is_subdir);
 EXPORT_SYMBOL(get_unused_fd);
+EXPORT_SYMBOL(put_unused_fd);
 EXPORT_SYMBOL(vfs_create);
 EXPORT_SYMBOL(vfs_mkdir);
 EXPORT_SYMBOL(vfs_mknod);
@@ -268,6 +276,7 @@
 EXPORT_SYMBOL(ROOT_DEV);
 EXPORT_SYMBOL(__find_get_page);
 EXPORT_SYMBOL(__find_lock_page);
+EXPORT_SYMBOL(find_trylock_page);
 EXPORT_SYMBOL(find_or_create_page);
 EXPORT_SYMBOL(grab_cache_page_nowait);
 EXPORT_SYMBOL(read_cache_page);
@@ -296,6 +305,7 @@
 EXPORT_SYMBOL(dentry_open);
 EXPORT_SYMBOL(filemap_nopage);
 EXPORT_SYMBOL(filemap_sync);
+EXPORT_SYMBOL(filemap_fdatawrite);
 EXPORT_SYMBOL(filemap_fdatasync);
 EXPORT_SYMBOL(filemap_fdatawait);
 EXPORT_SYMBOL(lock_page);
diff -urN linux-2.4.23-bk5/mm/filemap.c linux-2.4.23-bk6/mm/filemap.c
--- linux-2.4.23-bk5/mm/filemap.c	2003-12-08 02:54:07.000000000 -0800
+++ linux-2.4.23-bk6/mm/filemap.c	2003-12-08 02:54:10.000000000 -0800
@@ -548,6 +548,49 @@
 EXPORT_SYMBOL(fail_writepage);
 
 /**
+ *      filemap_fdatawrite - walk the list of dirty pages of the given address space
+ *     	and writepage() each unlocked page (does not wait on locked pages).
+ * 
+ *      @mapping: address space structure to write
+ *
+ */
+int filemap_fdatawrite(struct address_space * mapping)
+{
+	int ret = 0;
+	int (*writepage)(struct page *) = mapping->a_ops->writepage;
+
+	spin_lock(&pagecache_lock);
+
+	while (!list_empty(&mapping->dirty_pages)) {
+		struct page *page = list_entry(mapping->dirty_pages.prev, struct page, list);
+
+		list_del(&page->list);
+		list_add(&page->list, &mapping->locked_pages);
+
+		if (!PageDirty(page))
+			continue;
+
+		page_cache_get(page);
+		spin_unlock(&pagecache_lock);
+
+		if (!TryLockPage(page)) {
+			if (PageDirty(page)) {
+				int err;
+				ClearPageDirty(page);
+				err = writepage(page);
+				if (err && !ret)
+					ret = err;
+			} else
+				UnlockPage(page);
+		}
+		page_cache_release(page);
+		spin_lock(&pagecache_lock);
+	}
+	spin_unlock(&pagecache_lock);
+	return ret;
+}
+
+/**
  *      filemap_fdatasync - walk the list of dirty pages of the given address space
  *     	and writepage() all of them.
  * 
@@ -1702,6 +1745,17 @@
 	return size;
 }
 
+inline ssize_t do_generic_direct_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
+{
+	ssize_t retval;
+	loff_t pos = *ppos;
+
+	retval = generic_file_direct_IO(READ, filp, buf, count, pos);
+	if (retval > 0)
+		*ppos = pos + retval;
+	return retval;
+}
+
 /*
  * This is the "read()" routine for all filesystems
  * that can use the page cache directly.
@@ -1739,7 +1793,7 @@
 
  o_direct:
 	{
-		loff_t pos = *ppos, size;
+		loff_t size;
 		struct address_space *mapping = filp->f_dentry->d_inode->i_mapping;
 		struct inode *inode = mapping->host;
 
@@ -1749,11 +1803,8 @@
 		down_read(&inode->i_alloc_sem);
 		down(&inode->i_sem);
 		size = inode->i_size;
-		if (pos < size) {
-			retval = generic_file_direct_IO(READ, filp, buf, count, pos);
-			if (retval > 0)
-				*ppos = pos + retval;
-		}
+		if (*ppos < size)
+			retval = do_generic_direct_read(filp, buf, count, ppos);
 		up(&inode->i_sem);
 		up_read(&inode->i_alloc_sem);
 		UPDATE_ATIME(filp->f_dentry->d_inode);
diff -urN linux-2.4.23-bk5/mm/oom_kill.c linux-2.4.23-bk6/mm/oom_kill.c
--- linux-2.4.23-bk5/mm/oom_kill.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.23-bk6/mm/oom_kill.c	2003-12-08 02:54:10.000000000 -0800
@@ -202,6 +202,11 @@
  */
 void out_of_memory(void)
 {
+	/*
+	 * oom_lock protects out_of_memory()'s static variables.
+	 * It's a global lock; this is not performance-critical.
+	 */
+	static spinlock_t oom_lock = SPIN_LOCK_UNLOCKED;
 	static unsigned long first, last, count, lastkill;
 	unsigned long now, since;
 
@@ -211,6 +216,7 @@
 	if (nr_swap_pages > 0)
 		return;
 
+	spin_lock(&oom_lock);
 	now = jiffies;
 	since = now - last;
 	last = now;
@@ -229,14 +235,14 @@
 	 */
 	since = now - first;
 	if (since < HZ)
-		return;
+		goto out_unlock;
 
 	/*
 	 * If we have gotten only a few failures,
 	 * we're not really oom. 
 	 */
 	if (++count < 10)
-		return;
+		goto out_unlock;
 
 	/*
 	 * If we just killed a process, wait a while
@@ -245,17 +251,25 @@
 	 */
 	since = now - lastkill;
 	if (since < HZ*5)
-		return;
+		goto out_unlock;
 
 	/*
 	 * Ok, really out of memory. Kill something.
 	 */
 	lastkill = now;
+
+	/* oom_kill() can sleep */
+	spin_unlock(&oom_lock);
 	oom_kill();
+	spin_lock(&oom_lock);
 
 reset:
-	first = now;
+	if (first < now)
+		first = now;
 	count = 0;
+
+out_unlock:
+	spin_unlock(&oom_lock);
 }
 
 #endif	/* Unused file */
