## Automatically generated incremental diff
## From:   linux-2.4.13-pre6
## To:     linux-2.4.13
## Robot:  $Id: make-incremental-diff,v 1.8 2001/12/04 06:05:04 hpa Exp $

diff -urN linux-2.4.13-pre6/MAINTAINERS linux/MAINTAINERS
--- linux-2.4.13-pre6/MAINTAINERS	Mon Dec  3 23:19:39 2001
+++ linux/MAINTAINERS	Mon Dec  3 23:19:49 2001
@@ -1693,6 +1693,12 @@
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 
+YMFPCI YAMAHA PCI SOUND
+P:	Pete Zaitcev
+M:	zaitcev@yahoo.com
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+
 Z85230 SYNCHRONOUS DRIVER
 P:	Alan Cox
 M:	alan@redhat.com
diff -urN linux-2.4.13-pre6/Makefile linux/Makefile
--- linux-2.4.13-pre6/Makefile	Mon Dec  3 23:19:39 2001
+++ linux/Makefile	Mon Dec  3 23:19:49 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 13
-EXTRAVERSION =-pre6
+EXTRAVERSION =
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.13-pre6/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- linux-2.4.13-pre6/arch/i386/kernel/smp.c	Thu Oct  4 18:42:54 2001
+++ linux/arch/i386/kernel/smp.c	Mon Dec  3 23:19:49 2001
@@ -507,10 +507,9 @@
 	atomic_t started;
 	atomic_t finished;
 	int wait;
-} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
+};
 
 static struct call_data_struct * call_data;
-static struct call_data_struct call_data_array[NR_CPUS];
 
 /*
  * this function sends a 'generic call function' IPI to all other CPUs
@@ -532,45 +531,33 @@
  * hardware interrupt handler, you may call it from a bottom half handler.
  */
 {
-	struct call_data_struct *data;
-	int cpus = (cpu_online_map & ~(1 << smp_processor_id()));
+	struct call_data_struct data;
+	int cpus = smp_num_cpus-1;
 
 	if (!cpus)
 		return 0;
 
-	data = &call_data_array[smp_processor_id()];
-	
-	data->func = func;
-	data->info = info;
-	data->wait = wait;
+	data.func = func;
+	data.info = info;
+	atomic_set(&data.started, 0);
+	data.wait = wait;
 	if (wait)
-		atomic_set(&data->finished, 0);
-	/* We have do to this one last to make sure that the IPI service
-	 * code desn't get confused if it gets an unexpected repeat
-	 * trigger of an old IPI while we're still setting up the new
-	 * one. */
-	atomic_set(&data->started, 0);
-
-	local_bh_disable();
-	spin_lock(&call_lock);
-	call_data = data;
+		atomic_set(&data.finished, 0);
+
+	spin_lock_bh(&call_lock);
+	call_data = &data;
+	wmb();
 	/* Send a message to all other CPUs and wait for them to respond */
 	send_IPI_allbutself(CALL_FUNCTION_VECTOR);
 
 	/* Wait for response */
-	while (atomic_read(&data->started) != cpus)
+	while (atomic_read(&data.started) != cpus)
 		barrier();
 
-	/* It is now safe to reuse the "call_data" global, but we need
-	 * to keep local bottom-halves disabled until after waiters have
-	 * been acknowledged to prevent reuse of the per-cpu call data
-	 * entry. */
-	spin_unlock(&call_lock);
-
 	if (wait)
-		while (atomic_read(&data->finished) != cpus)
+		while (atomic_read(&data.finished) != cpus)
 			barrier();
-	local_bh_enable();
+	spin_unlock_bh(&call_lock);
 
 	return 0;
 }
@@ -620,17 +607,18 @@
 
 	ack_APIC_irq();
 	/*
-	 * Notify initiating CPU that I've grabbed the data and am about
-	 * to execute the function (and avoid servicing any single IPI
-	 * twice)
+	 * Notify initiating CPU that I've grabbed the data and am
+	 * about to execute the function
 	 */
-	if (test_and_set_bit(smp_processor_id(), &call_data->started))
-		return;
+	mb();
+	atomic_inc(&call_data->started);
 	/*
 	 * At this point the info structure may be out of scope unless wait==1
 	 */
 	(*func)(info);
-	if (wait)
-		set_bit(smp_processor_id(), &call_data->finished);
+	if (wait) {
+		mb();
+		atomic_inc(&call_data->finished);
+	}
 }
 
diff -urN linux-2.4.13-pre6/drivers/message/i2o/i2o_block.c linux/drivers/message/i2o/i2o_block.c
--- linux-2.4.13-pre6/drivers/message/i2o/i2o_block.c	Mon Dec  3 23:19:40 2001
+++ linux/drivers/message/i2o/i2o_block.c	Mon Dec  3 23:19:49 2001
@@ -47,6 +47,7 @@
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/stat.h>
+#include <linux/pci.h>
 #include <linux/errno.h>
 #include <linux/file.h>
 #include <linux/ioctl.h>
@@ -55,6 +56,7 @@
 #include <linux/blkpg.h>
 #include <linux/slab.h>
 #include <linux/hdreg.h>
+#include <linux/spinlock.h>
 
 #include <linux/notifier.h>
 #include <linux/reboot.h>
@@ -78,9 +80,9 @@
 
 //#define DRIVERDEBUG
 #ifdef DRIVERDEBUG
-#define DEBUG( s )
+#define DEBUG( s ) printk( s )
 #else
-#define DEBUG( s ) printk( s ) 
+#define DEBUG( s )
 #endif
 
 /*
@@ -508,7 +510,13 @@
 	u32 *m = (u32 *)msg;
 	u8 unit = (m[2]>>8)&0xF0;	/* low 4 bits are partition */
 	struct i2ob_device *dev = &i2ob_dev[(unit&0xF0)];
-	
+
+	/*
+	 *	Pull the lock over ready
+	 */	
+	 
+	spin_lock_prefetch(&io_request_lock);
+		
 	/*
 	 * FAILed message
 	 */
@@ -1140,7 +1148,7 @@
 	dev = &i2ob_dev[minor];
 	switch (cmd) {
 		case BLKGETSIZE:
-			return put_user(i2ob[minor].nr_sects, (unsigned long *) arg);
+			return put_user(i2ob[minor].nr_sects, (long *) arg);
 		case BLKGETSIZE64:
 			return put_user((u64)i2ob[minor].nr_sects << 9, (u64 *)arg);
 
@@ -1197,6 +1205,9 @@
 	if(!dev->i2odev)
 		return 0;
 
+	/* Sync the device so we don't get errors */
+	fsync_dev(inode->i_rdev);
+
 	if (dev->refcnt <= 0)
 		printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt);
 	dev->refcnt--;
@@ -1742,29 +1753,9 @@
 	spin_unlock_irqrestore(&io_request_lock, flags);
 
 	/*
-	 * Sync the device...this will force all outstanding I/Os
-	 * to attempt to complete, thus causing error messages.
-	 * We have to do this as the user could immediatelly create
-	 * a new volume that gets assigned the same minor number.
-	 * If there are still outstanding writes to the device,
-	 * that could cause data corruption on the new volume!
-	 *
-	 * The truth is that deleting a volume that you are currently
-	 * accessing will do _bad things_ to your system.  This 
-	 * handler will keep it from crashing, but must probably 
-	 * you'll have to do a 'reboot' to get the system running
-	 * properly.  Deleting disks you are using is dumb.  
-	 * Umount them first and all will be good!
-	 *
-	 * It's not this driver's job to protect the system from
-	 * dumb user mistakes :)
-	 */
-	if(i2ob_dev[unit].refcnt)
-		fsync_dev(MKDEV(MAJOR_NR,unit));
-
-	/*
 	 * Decrease usage count for module
 	 */	
+
 	while(i2ob_dev[unit].refcnt--)
 		MOD_DEC_USE_COUNT;
 
@@ -1986,10 +1977,11 @@
 EXPORT_NO_SYMBOLS;
 MODULE_AUTHOR("Red Hat Software");
 MODULE_DESCRIPTION("I2O Block Device OSM");
+MODULE_LICENSE("GPL");
+
 
 void cleanup_module(void)
 {
-	struct gendisk *gdp;
 	int i;
 	
 	if(evt_running) {
diff -urN linux-2.4.13-pre6/drivers/message/i2o/i2o_config.c linux/drivers/message/i2o/i2o_config.c
--- linux-2.4.13-pre6/drivers/message/i2o/i2o_config.c	Mon Dec  3 23:19:40 2001
+++ linux/drivers/message/i2o/i2o_config.c	Mon Dec  3 23:19:49 2001
@@ -961,5 +961,6 @@
 EXPORT_NO_SYMBOLS;
 MODULE_AUTHOR("Red Hat Software");
 MODULE_DESCRIPTION("I2O Configuration");
+MODULE_LICENSE("GPL");
 
 #endif
diff -urN linux-2.4.13-pre6/drivers/message/i2o/i2o_core.c linux/drivers/message/i2o/i2o_core.c
--- linux-2.4.13-pre6/drivers/message/i2o/i2o_core.c	Mon Dec  3 23:19:40 2001
+++ linux/drivers/message/i2o/i2o_core.c	Mon Dec  3 23:19:49 2001
@@ -246,8 +246,8 @@
 
                 /* Release the preserved msg by resubmitting it as a NOP */
 
-		preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
-		preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0;
+		preserved_msg[0] = cpu_to_le32(THREE_WORD_MSG_SIZE | SGL_OFFSET_0);
+		preserved_msg[1] = cpu_to_le32(I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0);
 		preserved_msg[2] = 0;
 		i2o_post_message(c, msg[7]);
 
@@ -606,7 +606,10 @@
 			up(&i2o_configuration_lock);
 
 			if(c->page_frame)
+			{
+				pci_unmap_single(c->pdev, c->page_frame_map, MSG_POOL_SIZE, PCI_DMA_FROMDEVICE);
 				kfree(c->page_frame);
+			}
 			if(c->hrt)
 				kfree(c->hrt);
 			if(c->lct)
@@ -1180,9 +1183,21 @@
 	while(mv!=0xFFFFFFFF)
 	{
 		struct i2o_handler *i;
-		m=(struct i2o_message *)bus_to_virt(mv);
+		/* Map the message from the page frame map to kernel virtual */
+		m=(struct i2o_message *)(mv - (unsigned long)c->page_frame_map + (unsigned long)c->page_frame);
 		msg=(u32*)m;
 
+		/*
+	 	 *	Ensure this message is seen coherently but cachably by
+		 *	the processor 
+	 	 */
+
+		pci_dma_sync_single(c->pdev, c->page_frame_map, MSG_FRAME_SIZE, PCI_DMA_FROMDEVICE);
+	
+		/*
+		 *	Despatch it
+	 	 */
+
 		i=i2o_handlers[m->initiator_context&(MAX_I2O_MODULES-1)];
 		if(i && i->reply)
 			i->reply(i,c,m);
@@ -1985,7 +2000,7 @@
 	msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6;
 	msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
 	msg[3] = 0;
-	msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */
+	msg[4] = (0<<16) | ((iop->unit+2) );      /* Host 0 IOP ID (unit + 2) */
 	msg[5] = 0;                               /* Segment 0 */
 
 	/* 
@@ -2258,11 +2273,21 @@
 
 	c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
 	if(c->page_frame==NULL) {
-		printk(KERN_CRIT "%s: Outbound Q initialize failed; out of memory.\n",
+		printk(KERN_ERR "%s: Outbound Q initialize failed; out of memory.\n",
 			c->name);
 		return -ENOMEM;
 	}
-	m=virt_to_bus(c->page_frame);
+
+	c->page_frame_map = pci_map_single(c->pdev, c->page_frame, MSG_POOL_SIZE, PCI_DMA_FROMDEVICE);
+
+	if(c->page_frame_map == 0)
+	{
+		kfree(c->page_frame);
+		printk(KERN_ERR "%s: Unable to map outbound queue.\n", c->name);
+		return -ENOMEM;
+	}
+
+	m = c->page_frame_map;
 
 	/* Post frames */
 
@@ -3427,6 +3452,8 @@
 
 MODULE_AUTHOR("Red Hat Software");
 MODULE_DESCRIPTION("I2O Core");
+MODULE_LICENSE("GPL");
+
 
 
 int init_module(void)
diff -urN linux-2.4.13-pre6/drivers/message/i2o/i2o_lan.c linux/drivers/message/i2o/i2o_lan.c
--- linux-2.4.13-pre6/drivers/message/i2o/i2o_lan.c	Mon Dec  3 23:19:40 2001
+++ linux/drivers/message/i2o/i2o_lan.c	Mon Dec  3 23:19:49 2001
@@ -1,5 +1,5 @@
 /*
- *	drivers/message/i2o/i2o_lan.c
+ *	drivers/i2o/i2o_lan.c
  *
  * 	I2O LAN CLASS OSM 		May 26th 2000
  *
@@ -1564,6 +1564,8 @@
 
 MODULE_AUTHOR("University of Helsinki, Department of Computer Science");
 MODULE_DESCRIPTION("I2O Lan OSM");
+MODULE_LICENSE("GPL");
+
 
 MODULE_PARM(max_buckets_out, "1-" __MODULE_STRING(I2O_LAN_MAX_BUCKETS_OUT) "i");
 MODULE_PARM_DESC(max_buckets_out, "Total number of buckets to post (1-)");
diff -urN linux-2.4.13-pre6/drivers/message/i2o/i2o_pci.c linux/drivers/message/i2o/i2o_pci.c
--- linux-2.4.13-pre6/drivers/message/i2o/i2o_pci.c	Mon Dec  3 23:19:40 2001
+++ linux/drivers/message/i2o/i2o_pci.c	Mon Dec  3 23:19:49 2001
@@ -219,7 +219,11 @@
 		printk(KERN_INFO "I2O: MTRR workaround for Intel i960 processor\n"); 
 		c->bus.pci.mtrr_reg1 =	mtrr_add(c->mem_phys, 65536, MTRR_TYPE_UNCACHABLE, 1);
 		if(c->bus.pci.mtrr_reg1< 0)
+		{
 			printk(KERN_INFO "i2o_pci: Error in setting MTRR_TYPE_UNCACHABLE\n");
+			mtrr_del(c->bus.pci.mtrr_reg0, c->mem_phys, size);
+			c->bus.pci.mtrr_reg0 = -1;
+		}
 	}
 
 #endif
@@ -277,6 +281,14 @@
 	{
 		if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O)
 			continue;
+		if(dev->vendor == PCI_VENDOR_ID_DPT)
+		{
+			if(dev->device == 0xA501 || dev->device == 0xA511)
+			{
+				printk(KERN_INFO "i2o: Skipping Adaptec/DPT I2O raid with preferred native driver.\n");
+				continue;
+			}
+		}
 		if((dev->class&0xFF)>1)
 		{
 			printk(KERN_INFO "i2o: I2O Controller found but does not support I2O 1.5 (skipping).\n");
@@ -367,6 +379,8 @@
 
 MODULE_AUTHOR("Red Hat Software");
 MODULE_DESCRIPTION("I2O PCI Interface");
+MODULE_LICENSE("GPL");
+
 
 #else
 void __init i2o_pci_init(void)
diff -urN linux-2.4.13-pre6/drivers/message/i2o/i2o_proc.c linux/drivers/message/i2o/i2o_proc.c
--- linux-2.4.13-pre6/drivers/message/i2o/i2o_proc.c	Mon Dec  3 23:19:40 2001
+++ linux/drivers/message/i2o/i2o_proc.c	Mon Dec  3 23:19:49 2001
@@ -299,14 +299,13 @@
 
 static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED;
 
-int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len, 
+int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int count, 
 		      int *eof, void *data)
 {
 	struct i2o_controller *c = (struct i2o_controller *)data;
 	i2o_hrt *hrt = (i2o_hrt *)c->hrt;
 	u32 bus;
-	int count;
-	int i;
+	int len, i;
 
 	spin_lock(&i2o_proc_lock);
 
@@ -320,9 +319,7 @@
 		return len;
 	}
 
-	count = hrt->num_entries;
-
-	if((count * hrt->entry_len + 8) > 2048) {
+	if((hrt->num_entries * hrt->entry_len + 8) > 2048) {
 		printk(KERN_WARNING "i2o_proc: HRT does not fit into buffer\n");
 		len += sprintf(buf+len,
 			       "HRT table too big to fit in buffer.\n");
@@ -331,9 +328,9 @@
 	}
 	
 	len += sprintf(buf+len, "HRT has %d entries of %d bytes each.\n",
-		       count, hrt->entry_len << 2);
+		       hrt->num_entries, hrt->entry_len << 2);
 
-	for(i = 0; i < count; i++)
+	for(i = 0; i < hrt->num_entries && len < count; i++)
 	{
 		len += sprintf(buf+len, "Entry %d:\n", i);
 		len += sprintf(buf+len, "   Adapter ID: %0#10x\n", 
@@ -3297,7 +3294,7 @@
 void i2o_proc_dev_del(struct i2o_controller *c, struct i2o_device *d)
 {
 #ifdef DRIVERDEBUG
-	printk(KERN_INFO, "Deleting device %d from iop%d\n", 
+	printk(KERN_INFO "Deleting device %d from iop%d\n", 
 		d->lct_data.tid, c->unit);
 #endif
 
@@ -3365,6 +3362,7 @@
 
 MODULE_AUTHOR("Deepak Saxena");
 MODULE_DESCRIPTION("I2O procfs Handler");
+MODULE_LICENSE("GPL");
 
 static void __exit i2o_proc_exit(void)
 {
diff -urN linux-2.4.13-pre6/drivers/message/i2o/i2o_scsi.c linux/drivers/message/i2o/i2o_scsi.c
--- linux-2.4.13-pre6/drivers/message/i2o/i2o_scsi.c	Mon Dec  3 23:19:40 2001
+++ linux/drivers/message/i2o/i2o_scsi.c	Mon Dec  3 23:19:49 2001
@@ -41,6 +41,7 @@
 #include <linux/timer.h>
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
+#include <linux/prefetch.h>
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -152,7 +153,9 @@
 	Scsi_Cmnd *current_command;
 	u32 *m = (u32 *)msg;
 	u8 as,ds,st;
-	
+
+	spin_lock_prefetch(&io_request_lock);		
+
 	if(m[0] & (1<<13))
 	{
 		printk("IOP fail.\n");
@@ -201,7 +204,9 @@
 		}
 		return;
 	}
-			
+	
+	prefetchw(&queue_depth);
+		
 	
 	/*
 	 *	Low byte is device status, next is adapter status,
@@ -548,6 +553,11 @@
 	 
 	host = SCpnt->host;
 	hostdata = (struct i2o_scsi_host *)host->hostdata;
+	 
+	c = hostdata->controller;
+	prefetch(c);
+	prefetchw(&queue_depth);
+
 	SCpnt->scsi_done = done;
 	
 	if(SCpnt->target > 15)
@@ -575,7 +585,6 @@
 	
 	dprintk(("Real scsi messages.\n"));
 
-	c = hostdata->controller;
 	
 	/*
 	 *	Obtain an I2O message. Right now we _have_ to obtain one
@@ -906,6 +915,8 @@
 }
 
 MODULE_AUTHOR("Red Hat Software");
+MODULE_LICENSE("GPL");
+
 
 static Scsi_Host_Template driver_template = I2OSCSI;
 
diff -urN linux-2.4.13-pre6/drivers/scsi/dpt_i2o.c linux/drivers/scsi/dpt_i2o.c
--- linux-2.4.13-pre6/drivers/scsi/dpt_i2o.c	Mon Dec  3 23:19:40 2001
+++ linux/drivers/scsi/dpt_i2o.c	Mon Dec  3 23:19:50 2001
@@ -78,9 +78,9 @@
 	{'d', 'P', 't', 'S', 'i', 'G'}, SIG_VERSION,
 #ifdef __i386__
 	PROC_INTEL, PROC_386 | PROC_486 | PROC_PENTIUM | PROC_SEXIUM,
-#elif defined __ia64__
+#elif defined(__ia64__)
 	PROC_INTEL, PROC_IA64,
-#elif define __sparc__
+#elif defined(__sparc__)
 	PROC_ULTRASPARC,
 #elif defined(__alpha__)
 	PROC_ALPHA ,
@@ -1152,12 +1152,12 @@
 	timeout *= HZ;
 	if((status = adpt_i2o_post_this(pHba, msg, len)) == 0){
 		if(!timeout){
-			current->state = TASK_INTERRUPTIBLE;
+			set_current_state(TASK_INTERRUPTIBLE);
 			spin_unlock_irq(&io_request_lock);
 			schedule();
 			spin_lock_irq(&io_request_lock);
 		} else {
-			current->state = TASK_INTERRUPTIBLE;
+			set_current_state(TASK_INTERRUPTIBLE);
 			spin_unlock_irq(&io_request_lock);
 			schedule_timeout(timeout*HZ);
 			spin_lock_irq(&io_request_lock);
@@ -1799,11 +1799,11 @@
 
 #if defined __i386__ 
 	adpt_i386_info(&si);
-#elif defined __ia64__
+#elif defined (__ia64__)
 	adpt_ia64_info(&si);
-#elif define __sparc__
+#elif defined(__sparc__)
 	adpt_sparc_info(&si);
-#elif defined __alpha__ 
+#elif defined (__alpha__)
 	adpt_alpha_info(&si);
 #else
 	si.processorType = 0xff ;
diff -urN linux-2.4.13-pre6/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c
--- linux-2.4.13-pre6/drivers/sound/ymfpci.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/sound/ymfpci.c	Mon Dec  3 23:19:50 2001
@@ -66,10 +66,13 @@
  * I do not believe in debug levels as I never can guess what
  * part of the code is going to be problematic in the future.
  * Don't forget to run your klogd with -c 8.
+ *
+ * Example (do not remove):
+ * #define YMFDBG(fmt, arg...)  do{ printk(KERN_DEBUG fmt, ##arg); }while(0)
  */
-/* #define YMFDBG(fmt, arg...)  do{ printk(KERN_DEBUG fmt, ##arg); }while(0) */
-#define YMFDBGW(fmt, arg...)  /* */
-#define YMFDBGI(fmt, arg...)  /* */
+#define YMFDBGW(fmt, arg...)  /* */	/* write counts */
+#define YMFDBGI(fmt, arg...)  /* */	/* interrupts */
+#define YMFDBGX(fmt, arg...)  /* */	/* ioctl */
 
 static int ymf_playback_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd);
 static void ymf_capture_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd);
@@ -330,7 +333,7 @@
 	int w_16;
 	unsigned bufsize;
 	unsigned long flags;
-	int redzone;
+	int redzone, redfrags;
 	int ret;
 
 	w_16 = ymf_pcm_format_width(state->format.format) == 16;
@@ -352,36 +355,27 @@
 	 * Import what Doom might have set with SNDCTL_DSP_SETFRAGMENT.
 	 */
 	bufsize = PAGE_SIZE << dmabuf->buforder;
-	/* lets hand out reasonable big ass buffers by default */
-	dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2);
+	/* By default we give 4 big buffers. */
+	dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT - 2);
 	if (dmabuf->ossfragshift > 3 &&
 	    dmabuf->ossfragshift < dmabuf->fragshift) {
+		/* If OSS set smaller fragments, give more smaller buffers. */
 		dmabuf->fragshift = dmabuf->ossfragshift;
 	}
-	dmabuf->numfrag = bufsize >> dmabuf->fragshift;
-	while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) {
-		dmabuf->fragshift--;
-		dmabuf->numfrag = bufsize >> dmabuf->fragshift;
-	}
 	dmabuf->fragsize = 1 << dmabuf->fragshift;
-	dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
 
-	if (dmabuf->ossmaxfrags >= 2 && dmabuf->ossmaxfrags < dmabuf->numfrag) {
-		dmabuf->numfrag = dmabuf->ossmaxfrags;
-		dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
+	dmabuf->numfrag = bufsize >> dmabuf->fragshift;
+	dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
 
+	if (dmabuf->ossmaxfrags >= 2) {
 		redzone = ymf_calc_lend(state->format.rate);
-		redzone <<= (state->format.shift + 1);
-		if (dmabuf->dmasize < redzone*3) {
-			/*
-			 * The driver works correctly with minimum dmasize
-			 * of redzone*2, but it produces stoppage and clicks.
-			 * So, make it little larger for smoother sound.
-			 * XXX Make dmasize a wholy divisible by fragsize.
-			 */
-//			printk(KERN_ERR "ymfpci: dmasize=%d < redzone=%d * 3\n",
-//			    dmabuf->dmasize, redzone);
-			dmabuf->dmasize = redzone*3;
+		redzone <<= state->format.shift;
+		redzone *= 3;
+		redfrags = (redzone + dmabuf->fragsize-1) >> dmabuf->fragshift;
+
+		if (dmabuf->ossmaxfrags + redfrags < dmabuf->numfrag) {
+			dmabuf->numfrag = dmabuf->ossmaxfrags + redfrags;
+			dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
 		}
 	}
 
@@ -1440,7 +1434,7 @@
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&dmabuf->wait, &waita);
 
-	YMFDBGW("ymf_write: dmabuf.count %d\n", dmabuf->count);
+	YMFDBGW("ymf_write: ret %d dmabuf.count %d\n", ret, dmabuf->count);
 	return ret;
 }
 
@@ -1794,6 +1788,7 @@
 	case SNDCTL_DSP_SETSYNCRO:
 	case SOUND_PCM_WRITE_FILTER:
 	case SOUND_PCM_READ_FILTER:
+		YMFDBGX("ymf_ioctl: cmd 0x%x unsupported\n", cmd);
 		return -ENOTTY;
 
 	default:
@@ -1802,7 +1797,8 @@
 		 * or perhaps they expect "universal" ioctls,
 		 * for instance we get SNDCTL_TMR_CONTINUE here.
 		 */
-		 break;
+		YMFDBGX("ymf_ioctl: cmd 0x%x unknown\n", cmd);
+		break;
 	}
 	return -ENOTTY;
 }
diff -urN linux-2.4.13-pre6/fs/buffer.c linux/fs/buffer.c
--- linux-2.4.13-pre6/fs/buffer.c	Mon Dec  3 23:19:41 2001
+++ linux/fs/buffer.c	Mon Dec  3 23:19:50 2001
@@ -112,15 +112,16 @@
 		int dummy5;	/* unused */
 	} b_un;
 	unsigned int data[N_PARAM];
-} bdf_prm = {{30, 64, 64, 256, 5*HZ, 30*HZ, 60, 0, 0}};
+} bdf_prm = {{40, 0, 0, 0, 5*HZ, 30*HZ, 60, 0, 0}};
 
 /* These are the min and max parameter values that we will allow to be assigned */
 int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   1*HZ,   0, 0, 0};
 int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,10000*HZ, 6000*HZ, 100, 0, 0};
 
-inline void unlock_buffer(struct buffer_head *bh)
+void unlock_buffer(struct buffer_head *bh)
 {
 	clear_bit(BH_Wait_IO, &bh->b_state);
+	clear_bit(BH_launder, &bh->b_state);
 	clear_bit(BH_Lock, &bh->b_state);
 	smp_mb__after_clear_bit();
 	if (waitqueue_active(&bh->b_wait))
@@ -2331,29 +2332,40 @@
 	return 1;
 }
 
-static int sync_page_buffers(struct buffer_head *bh, unsigned int gfp_mask)
+static int sync_page_buffers(struct buffer_head *head, unsigned int gfp_mask)
 {
-	struct buffer_head * p = bh;
-	int tryagain = 1;
+	struct buffer_head * bh = head;
+	int tryagain = 0;
 
 	do {
-		if (buffer_dirty(p) || buffer_locked(p)) {
-			if (test_and_set_bit(BH_Wait_IO, &p->b_state)) {
-				if (buffer_dirty(p)) {
-					ll_rw_block(WRITE, 1, &p);
-					tryagain = 0;
-				} else if (buffer_locked(p)) {
-					if (gfp_mask & __GFP_WAITBUF) {
-						wait_on_buffer(p);
-						tryagain = 1;
-					} else
-						tryagain = 0;
-				}
-			} else
-				tryagain = 0;
+		if (!buffer_dirty(bh) && !buffer_locked(bh))
+			continue;
+
+		/* Don't start IO first time around.. */
+		if (!test_and_set_bit(BH_Wait_IO, &bh->b_state))
+			continue;
+
+		/* Second time through we start actively writing out.. */
+		if (test_and_set_bit(BH_Lock, &bh->b_state)) {
+			if (!test_bit(BH_launder, &bh->b_state))
+				continue;
+			wait_on_buffer(bh);
+			tryagain = 1;
+			continue;
+		}
+
+		if (!atomic_set_buffer_clean(bh)) {
+			unlock_buffer(bh);
+			continue;
 		}
-		p = p->b_this_page;
-	} while (p != bh);
+
+		__mark_buffer_clean(bh);
+		get_bh(bh);
+		set_bit(BH_launder, &bh->b_state);
+		bh->b_end_io = end_buffer_io_sync;
+		submit_bh(WRITE, bh);
+		tryagain = 0;
+	} while ((bh = bh->b_this_page) != head);
 
 	return tryagain;
 }
diff -urN linux-2.4.13-pre6/fs/ntfs/fs.c linux/fs/ntfs/fs.c
--- linux-2.4.13-pre6/fs/ntfs/fs.c	Sun Sep 30 11:42:44 2001
+++ linux/fs/ntfs/fs.c	Mon Dec  3 23:19:50 2001
@@ -1159,6 +1159,7 @@
  */
 MODULE_AUTHOR("Anton Altaparmakov <aia21@cus.cam.ac.uk>");
 MODULE_DESCRIPTION("Linux NTFS driver");
+MODULE_LICENSE("GPL");
 #ifdef DEBUG
 MODULE_PARM(ntdebug, "i");
 MODULE_PARM_DESC(ntdebug, "Debug level");
diff -urN linux-2.4.13-pre6/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.4.13-pre6/include/linux/fs.h	Mon Dec  3 23:19:41 2001
+++ linux/include/linux/fs.h	Mon Dec  3 23:19:50 2001
@@ -214,7 +214,8 @@
 	BH_Mapped,	/* 1 if the buffer has a disk mapping */
 	BH_New,		/* 1 if the buffer is new and not yet written out */
 	BH_Async,	/* 1 if the buffer is under end_buffer_io_async I/O */
-	BH_Wait_IO,	/* 1 if we should throttle on this buffer */
+	BH_Wait_IO,	/* 1 if we should write out this buffer */
+	BH_launder,	/* 1 if we should throttle on this buffer */
 
 	BH_PrivateStart,/* not a state bit, but the first bit available
 			 * for private allocation by other entities
diff -urN linux-2.4.13-pre6/include/linux/locks.h linux/include/linux/locks.h
--- linux-2.4.13-pre6/include/linux/locks.h	Wed Oct 10 23:45:20 2001
+++ linux/include/linux/locks.h	Mon Dec  3 23:19:50 2001
@@ -26,7 +26,7 @@
 		__wait_on_buffer(bh);
 }
 
-extern void unlock_buffer(struct buffer_head *bh);
+extern void FASTCALL(unlock_buffer(struct buffer_head *bh));
 
 /*
  * super-block locking. Again, interrupts may only unlock
diff -urN linux-2.4.13-pre6/include/linux/mm.h linux/include/linux/mm.h
--- linux-2.4.13-pre6/include/linux/mm.h	Wed Oct 10 23:44:38 2001
+++ linux/include/linux/mm.h	Mon Dec  3 23:19:50 2001
@@ -279,6 +279,7 @@
 #define PG_checked		12	/* kill me in 2.5.<early>. */
 #define PG_arch_1		13
 #define PG_reserved		14
+#define PG_launder		15	/* written out by VM pressure.. */
 
 /* Make it prettier to test the above... */
 #define Page_Uptodate(page)	test_bit(PG_uptodate, &(page)->flags)
@@ -292,6 +293,8 @@
 #define TryLockPage(page)	test_and_set_bit(PG_locked, &(page)->flags)
 #define PageChecked(page)	test_bit(PG_checked, &(page)->flags)
 #define SetPageChecked(page)	set_bit(PG_checked, &(page)->flags)
+#define PageLaunder(page)	test_bit(PG_launder, &(page)->flags)
+#define SetPageLaunder(page)	set_bit(PG_launder, &(page)->flags)
 
 extern void __set_page_dirty(struct page *);
 
@@ -308,6 +311,7 @@
  * parallel wait_on_page).
  */
 #define UnlockPage(page)	do { \
+					clear_bit(PG_launder, &(page)->flags); \
 					smp_mb__before_clear_bit(); \
 					if (!test_and_clear_bit(PG_locked, &(page)->flags)) BUG(); \
 					smp_mb__after_clear_bit(); \
@@ -550,17 +554,16 @@
 #define __GFP_IO	0x40	/* Can start low memory physical IO? */
 #define __GFP_HIGHIO	0x80	/* Can start high mem physical IO? */
 #define __GFP_FS	0x100	/* Can call down to low-level FS? */
-#define __GFP_WAITBUF	0x200	/* Can we wait for buffers to complete? */
 
 #define GFP_NOHIGHIO	(__GFP_HIGH | __GFP_WAIT | __GFP_IO)
 #define GFP_NOIO	(__GFP_HIGH | __GFP_WAIT)
-#define GFP_NOFS	(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_WAITBUF)
+#define GFP_NOFS	(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO)
 #define GFP_ATOMIC	(__GFP_HIGH)
-#define GFP_USER	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_WAITBUF | __GFP_FS)
-#define GFP_HIGHUSER	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_WAITBUF | __GFP_FS | __GFP_HIGHMEM)
-#define GFP_KERNEL	(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_WAITBUF | __GFP_FS)
-#define GFP_NFS		(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_WAITBUF | __GFP_FS)
-#define GFP_KSWAPD	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_WAITBUF | __GFP_FS)
+#define GFP_USER	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
+#define GFP_HIGHUSER	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS | __GFP_HIGHMEM)
+#define GFP_KERNEL	(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
+#define GFP_NFS		(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
+#define GFP_KSWAPD	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
 
 /* Flag - indicates that the buffer will be suitable for DMA.  Ignored on some
    platforms, used as appropriate on others */
diff -urN linux-2.4.13-pre6/include/linux/slab.h linux/include/linux/slab.h
--- linux-2.4.13-pre6/include/linux/slab.h	Wed Oct 10 23:44:38 2001
+++ linux/include/linux/slab.h	Mon Dec  3 23:19:50 2001
@@ -24,7 +24,7 @@
 #define	SLAB_NFS		GFP_NFS
 #define	SLAB_DMA		GFP_DMA
 
-#define SLAB_LEVEL_MASK		(__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_HIGHIO|__GFP_WAITBUF|__GFP_FS)
+#define SLAB_LEVEL_MASK		(__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_HIGHIO|__GFP_FS)
 #define	SLAB_NO_GROW		0x00001000UL	/* don't grow a cache */
 
 /* flags to pass to kmem_cache_create().
diff -urN linux-2.4.13-pre6/include/linux/swap.h linux/include/linux/swap.h
--- linux-2.4.13-pre6/include/linux/swap.h	Mon Dec  3 23:19:41 2001
+++ linux/include/linux/swap.h	Mon Dec  3 23:19:50 2001
@@ -102,15 +102,13 @@
 extern void FASTCALL(lru_cache_del(struct page *));
 
 extern void FASTCALL(deactivate_page(struct page *));
-extern void FASTCALL(deactivate_page_nolock(struct page *));
 extern void FASTCALL(activate_page(struct page *));
-extern void FASTCALL(activate_page_nolock(struct page *));
 
 extern void swap_setup(void);
 
 /* linux/mm/vmscan.c */
 extern wait_queue_head_t kswapd_wait;
-extern int FASTCALL(try_to_free_pages(unsigned int, unsigned int));
+extern int FASTCALL(try_to_free_pages(zone_t *, unsigned int, unsigned int));
 
 /* linux/mm/page_io.c */
 extern void rw_swap_page(int, struct page *);
diff -urN linux-2.4.13-pre6/kernel/exit.c linux/kernel/exit.c
--- linux-2.4.13-pre6/kernel/exit.c	Mon Sep 10 13:04:33 2001
+++ linux/kernel/exit.c	Mon Dec  3 23:19:50 2001
@@ -149,28 +149,21 @@
 }
 
 /*
- * When we die, we re-parent all our children.
- * Try to give them to another thread in our process
- * group, and if no such member exists, give it to
+ * When we die, we re-parent all our children to
  * the global child reaper process (ie "init")
  */
 static inline void forget_original_parent(struct task_struct * father)
 {
-	struct task_struct * p, *reaper;
+	struct task_struct * p;
 
 	read_lock(&tasklist_lock);
 
-	/* Next in our thread group */
-	reaper = next_thread(father);
-	if (reaper == father)
-		reaper = child_reaper;
-
 	for_each_task(p) {
 		if (p->p_opptr == father) {
 			/* We dont want people slaying init */
 			p->exit_signal = SIGCHLD;
 			p->self_exec_id++;
-			p->p_opptr = reaper;
+			p->p_opptr = child_reaper;
 			if (p->pdeath_signal) send_sig(p->pdeath_signal, p, 0);
 		}
 	}
diff -urN linux-2.4.13-pre6/mm/highmem.c linux/mm/highmem.c
--- linux-2.4.13-pre6/mm/highmem.c	Tue Sep 18 14:10:43 2001
+++ linux/mm/highmem.c	Mon Dec  3 23:19:50 2001
@@ -327,7 +327,6 @@
 	struct list_head *tmp;
 	struct page *page;
 
-repeat_alloc:
 	page = alloc_page(GFP_NOHIGHIO);
 	if (page)
 		return page;
@@ -337,6 +336,7 @@
 	 */
 	wakeup_bdflush();
 
+repeat_alloc:
 	/*
 	 * Try to allocate from the emergency pool.
 	 */
@@ -365,7 +365,6 @@
 	struct list_head *tmp;
 	struct buffer_head *bh;
 
-repeat_alloc:
 	bh = kmem_cache_alloc(bh_cachep, SLAB_NOHIGHIO);
 	if (bh)
 		return bh;
@@ -375,6 +374,7 @@
 	 */
 	wakeup_bdflush();
 
+repeat_alloc:
 	/*
 	 * Try to allocate from the emergency pool.
 	 */
diff -urN linux-2.4.13-pre6/mm/page_alloc.c linux/mm/page_alloc.c
--- linux-2.4.13-pre6/mm/page_alloc.c	Mon Dec  3 23:19:41 2001
+++ linux/mm/page_alloc.c	Mon Dec  3 23:19:50 2001
@@ -242,7 +242,7 @@
 	current->allocation_order = order;
 	current->flags |= PF_MEMALLOC | PF_FREE_PAGES;
 
-	__freed = try_to_free_pages(gfp_mask, order);
+	__freed = try_to_free_pages(classzone, gfp_mask, order);
 
 	current->flags &= ~(PF_MEMALLOC | PF_FREE_PAGES);
 
@@ -467,20 +467,23 @@
 {
 	pg_data_t *pgdat = pgdat_list;
 	unsigned int sum = 0;
-	zonelist_t *zonelist;
-	zone_t **zonep, *zone;
 
 	do {
-		zonelist = pgdat->node_zonelists + (GFP_USER & GFP_ZONEMASK);
-		zonep = zonelist->zones;
+		zonelist_t *zonelist = pgdat->node_zonelists + (GFP_USER & GFP_ZONEMASK);
+		zone_t **zonep = zonelist->zones;
+		zone_t *zone;
 
-		for (zone = *zonep++; zone; zone = *zonep++)
-			sum += zone->free_pages;
+		for (zone = *zonep++; zone; zone = *zonep++) {
+			unsigned long size = zone->size;
+			unsigned long high = zone->pages_high;
+			if (size > high)
+				sum += size - high;
+		}
 
 		pgdat = pgdat->node_next;
 	} while (pgdat);
 
-	return sum + nr_active_pages + nr_inactive_pages;
+	return sum;
 }
 
 #if CONFIG_HIGHMEM
@@ -497,6 +500,8 @@
 }
 #endif
 
+#define K(x) ((x) << (PAGE_SHIFT-10))
+
 /*
  * Show free area list (used inside shift_scroll-lock stuff)
  * We also calculate the percentage fragmentation. We do this by counting the
@@ -519,21 +524,17 @@
 			printk("Zone:%s freepages:%6lukB min:%6luKB low:%6lukB " 
 				       "high:%6lukB\n", 
 					zone->name,
-					(zone->free_pages)
-					<< ((PAGE_SHIFT-10)),
-					zone->pages_min
-					<< ((PAGE_SHIFT-10)),
-					zone->pages_low
-					<< ((PAGE_SHIFT-10)),
-					zone->pages_high
-					<< ((PAGE_SHIFT-10)));
+					K(zone->free_pages),
+					K(zone->pages_min),
+					K(zone->pages_low),
+					K(zone->pages_high));
 			
 		tmpdat = tmpdat->node_next;
 	}
 
 	printk("Free pages:      %6dkB (%6dkB HighMem)\n",
-		nr_free_pages() << (PAGE_SHIFT-10),
-		nr_free_highpages() << (PAGE_SHIFT-10));
+		K(nr_free_pages()),
+		K(nr_free_highpages()));
 
 	printk("( Active: %d, inactive: %d, free: %d )\n",
 	       nr_active_pages,
@@ -564,7 +565,7 @@
 			}
 			spin_unlock_irqrestore(&zone->lock, flags);
 		}
-		printk("= %lukB)\n", total * (PAGE_SIZE>>10));
+		printk("= %lukB)\n", K(total));
 	}
 
 #ifdef SWAP_CACHE_INFO
diff -urN linux-2.4.13-pre6/mm/swap.c linux/mm/swap.c
--- linux-2.4.13-pre6/mm/swap.c	Mon Dec  3 23:19:41 2001
+++ linux/mm/swap.c	Mon Dec  3 23:19:50 2001
@@ -48,7 +48,7 @@
  * called on a page which is not on any of the lists, the
  * page is left alone.
  */
-void deactivate_page_nolock(struct page * page)
+static inline void deactivate_page_nolock(struct page * page)
 {
 	if (PageActive(page)) {
 		del_page_from_active_list(page);
@@ -66,7 +66,7 @@
 /*
  * Move an inactive page to the active list.
  */
-void activate_page_nolock(struct page * page)
+static inline void activate_page_nolock(struct page * page)
 {
 	if (PageInactive(page)) {
 		del_page_from_inactive_list(page);
diff -urN linux-2.4.13-pre6/mm/vmscan.c linux/mm/vmscan.c
--- linux-2.4.13-pre6/mm/vmscan.c	Mon Dec  3 23:19:41 2001
+++ linux/mm/vmscan.c	Mon Dec  3 23:19:50 2001
@@ -33,8 +33,6 @@
  */
 #define DEF_PRIORITY (6)
 
-#define page_zone_plenty(page) ((page)->zone->free_pages > (page)->zone->pages_high)
-
 /*
  * The swap-out function returns 1 if it successfully
  * scanned all the pages it was asked to (`count').
@@ -45,7 +43,7 @@
  */
 
 /* mm->page_table_lock is held. mmap_sem is not held */
-static inline int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* vma, unsigned long address, pte_t * page_table, struct page *page)
+static inline int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* vma, unsigned long address, pte_t * page_table, struct page *page, zone_t * classzone)
 {
 	pte_t pte;
 	swp_entry_t entry;
@@ -53,11 +51,16 @@
 	/* Don't look at this pte if it's been accessed recently. */
 	if (ptep_test_and_clear_young(page_table)) {
 		flush_tlb_page(vma, address);
+		mark_page_accessed(page);
 		return 0;
 	}
 
-	/* Don't bother replenishing zones that have tons of memory */
-	if (page_zone_plenty(page))
+	/* Don't bother unmapping pages that are active */
+	if (PageActive(page))
+		return 0;
+
+	/* Don't bother replenishing zones not under pressure.. */
+	if (!memclass(page->zone, classzone))
 		return 0;
 
 	if (TryLockPage(page))
@@ -146,7 +149,7 @@
 }
 
 /* mm->page_table_lock is held. mmap_sem is not held */
-static inline int swap_out_pmd(struct mm_struct * mm, struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long end, int count)
+static inline int swap_out_pmd(struct mm_struct * mm, struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long end, int count, zone_t * classzone)
 {
 	pte_t * pte;
 	unsigned long pmd_end;
@@ -170,7 +173,7 @@
 			struct page *page = pte_page(*pte);
 
 			if (VALID_PAGE(page) && !PageReserved(page)) {
-				count -= try_to_swap_out(mm, vma, address, pte, page);
+				count -= try_to_swap_out(mm, vma, address, pte, page, classzone);
 				if (!count) {
 					address += PAGE_SIZE;
 					break;
@@ -185,7 +188,7 @@
 }
 
 /* mm->page_table_lock is held. mmap_sem is not held */
-static inline int swap_out_pgd(struct mm_struct * mm, struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long end, int count)
+static inline int swap_out_pgd(struct mm_struct * mm, struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long end, int count, zone_t * classzone)
 {
 	pmd_t * pmd;
 	unsigned long pgd_end;
@@ -205,7 +208,7 @@
 		end = pgd_end;
 	
 	do {
-		count = swap_out_pmd(mm, vma, pmd, address, end, count);
+		count = swap_out_pmd(mm, vma, pmd, address, end, count, classzone);
 		if (!count)
 			break;
 		address = (address + PMD_SIZE) & PMD_MASK;
@@ -215,7 +218,7 @@
 }
 
 /* mm->page_table_lock is held. mmap_sem is not held */
-static inline int swap_out_vma(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long address, int count)
+static inline int swap_out_vma(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long address, int count, zone_t * classzone)
 {
 	pgd_t *pgdir;
 	unsigned long end;
@@ -230,7 +233,7 @@
 	if (address >= end)
 		BUG();
 	do {
-		count = swap_out_pgd(mm, vma, pgdir, address, end, count);
+		count = swap_out_pgd(mm, vma, pgdir, address, end, count, classzone);
 		if (!count)
 			break;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
@@ -245,7 +248,7 @@
 /*
  * Returns remaining count of pages to be swapped out by followup call.
  */
-static inline int swap_out_mm(struct mm_struct * mm, int count, int * mmcounter)
+static inline int swap_out_mm(struct mm_struct * mm, int count, int * mmcounter, zone_t * classzone)
 {
 	unsigned long address;
 	struct vm_area_struct* vma;
@@ -267,7 +270,7 @@
 			address = vma->vm_start;
 
 		for (;;) {
-			count = swap_out_vma(mm, vma, address, count);
+			count = swap_out_vma(mm, vma, address, count, classzone);
 			vma = vma->vm_next;
 			if (!vma)
 				break;
@@ -284,10 +287,10 @@
 	return count;
 }
 
-static int FASTCALL(swap_out(unsigned int priority, unsigned int gfp_mask, int nr_pages));
-static int swap_out(unsigned int priority, unsigned int gfp_mask, int nr_pages)
+static int FASTCALL(swap_out(unsigned int priority, unsigned int gfp_mask, zone_t * classzone));
+static int swap_out(unsigned int priority, unsigned int gfp_mask, zone_t * classzone)
 {
-	int counter;
+	int counter, nr_pages = SWAP_CLUSTER_MAX;
 	struct mm_struct *mm;
 
 	/* Then, look at the other mm's */
@@ -312,7 +315,7 @@
 		atomic_inc(&mm->mm_users);
 		spin_unlock(&mmlist_lock);
 
-		nr_pages = swap_out_mm(mm, nr_pages, &counter);
+		nr_pages = swap_out_mm(mm, nr_pages, &counter, classzone);
 
 		mmput(mm);
 
@@ -327,13 +330,13 @@
 	return 0;
 }
 
-static int FASTCALL(shrink_cache(int nr_pages, int max_scan, unsigned int gfp_mask));
-static int shrink_cache(int nr_pages, int max_scan, unsigned int gfp_mask)
+static int FASTCALL(shrink_cache(int nr_pages, int max_mapped, zone_t * classzone, unsigned int gfp_mask));
+static int shrink_cache(int nr_pages, int max_mapped, zone_t * classzone, unsigned int gfp_mask)
 {
 	struct list_head * entry;
 
 	spin_lock(&pagemap_lru_lock);
-	while (max_scan && (entry = inactive_list.prev) != &inactive_list) {
+	while (max_mapped && (entry = inactive_list.prev) != &inactive_list) {
 		struct page * page;
 
 		if (unlikely(current->need_resched)) {
@@ -351,23 +354,28 @@
 
 		list_del(entry);
 		list_add(entry, &inactive_list);
-		if (PageTestandClearReferenced(page))
-			continue;
 
-		max_scan--;
-		if (unlikely(page_zone_plenty(page)))
+		if (!memclass(page->zone, classzone))
 			continue;
 
 		/* Racy check to avoid trylocking when not worthwhile */
 		if (!page->buffers && page_count(page) != 1)
-			continue;
+			goto page_mapped;
 
 		/*
 		 * The page is locked. IO in progress?
 		 * Move it to the back of the list.
 		 */
-		if (unlikely(TryLockPage(page)))
+		if (unlikely(TryLockPage(page))) {
+			if (PageLaunder(page) && (gfp_mask & __GFP_FS)) {
+				page_cache_get(page);
+				spin_unlock(&pagemap_lru_lock);
+				wait_on_page(page);
+				page_cache_release(page);
+				spin_lock(&pagemap_lru_lock);
+			}
 			continue;
+		}
 
 		if (PageDirty(page) && is_page_cache_freeable(page) && page->mapping) {
 			/*
@@ -383,6 +391,7 @@
 			writepage = page->mapping->a_ops->writepage;
 			if ((gfp_mask & __GFP_FS) && writepage) {
 				ClearPageDirty(page);
+				SetPageLaunder(page);
 				page_cache_get(page);
 				spin_unlock(&pagemap_lru_lock);
 
@@ -462,7 +471,10 @@
 		if (!is_page_cache_freeable(page) || PageDirty(page)) {
 			spin_unlock(&pagecache_lock);
 			UnlockPage(page);
-			continue;
+page_mapped:
+			if (--max_mapped)
+				continue;
+			break;
 		}
 
 		/* point of no return */
@@ -522,8 +534,8 @@
 	spin_unlock(&pagemap_lru_lock);
 }
 
-static int FASTCALL(shrink_caches(int priority, unsigned int gfp_mask, int nr_pages));
-static int shrink_caches(int priority, unsigned int gfp_mask, int nr_pages)
+static int FASTCALL(shrink_caches(zone_t * classzone, int priority, unsigned int gfp_mask, int nr_pages));
+static int shrink_caches(zone_t * classzone, int priority, unsigned int gfp_mask, int nr_pages)
 {
 	int max_scan;
 	int chunk_size = nr_pages;
@@ -539,7 +551,7 @@
 	refill_inactive(ratio);
 
 	max_scan = nr_inactive_pages / priority;
-	nr_pages = shrink_cache(nr_pages, max_scan, gfp_mask);
+	nr_pages = shrink_cache(nr_pages, max_scan, classzone, gfp_mask);
 	if (nr_pages <= 0)
 		return 0;
 
@@ -552,18 +564,18 @@
 	return nr_pages;
 }
 
-int try_to_free_pages(unsigned int gfp_mask, unsigned int order)
+int try_to_free_pages(zone_t *classzone, unsigned int gfp_mask, unsigned int order)
 {
 	int ret = 0;
 	int priority = DEF_PRIORITY;
 	int nr_pages = SWAP_CLUSTER_MAX;
 
 	do {
-		nr_pages = shrink_caches(priority, gfp_mask, nr_pages);
+		nr_pages = shrink_caches(classzone, priority, gfp_mask, nr_pages);
 		if (nr_pages <= 0)
 			return 1;
 
-		ret |= swap_out(priority, gfp_mask, SWAP_CLUSTER_MAX << 2);
+		ret |= swap_out(priority, gfp_mask, classzone);
 	} while (--priority);
 
 	return ret;
@@ -595,7 +607,7 @@
 			schedule();
 		if (!zone->need_balance)
 			continue;
-		if (!try_to_free_pages(GFP_KSWAPD, 0)) {
+		if (!try_to_free_pages(zone, GFP_KSWAPD, 0)) {
 			zone->need_balance = 0;
 			__set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(HZ);
