]> git.neil.brown.name Git - history.git/commitdiff
v2.4.12.6 -> v2.4.13
authorLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 04:24:48 +0000 (20:24 -0800)
committerLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 04:24:48 +0000 (20:24 -0800)
  - page write-out throttling
  - Pete Zaitcev: ymfpci sound driver update (make Civ:CTP happy with it)
  - Alan Cox: i2o sync-up
  - Andrea Arcangeli: revert broken x86 smp_call_function patch
  - me: handle VM write load more gracefully. Merge parts of -aa VM

24 files changed:
MAINTAINERS
Makefile
arch/i386/kernel/smp.c
drivers/message/i2o/i2o_block.c
drivers/message/i2o/i2o_config.c
drivers/message/i2o/i2o_core.c
drivers/message/i2o/i2o_lan.c
drivers/message/i2o/i2o_pci.c
drivers/message/i2o/i2o_proc.c
drivers/message/i2o/i2o_scsi.c
drivers/scsi/dpt_i2o.c
drivers/sound/ymfpci.c
fs/buffer.c
fs/ntfs/fs.c
include/linux/fs.h
include/linux/locks.h
include/linux/mm.h
include/linux/slab.h
include/linux/swap.h
kernel/exit.c
mm/highmem.c
mm/page_alloc.c
mm/swap.c
mm/vmscan.c

index a9920bee1cb32bfd5f8290131dbbc1f15e1829ad..82ed0927ac00bbecb64cac2b2d054c5e2aa6a7b6 100644 (file)
@@ -1693,6 +1693,12 @@ M:       jpr@f6fbb.org
 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
index 131024afe3fc55248f2fd77132948acae6767f9a..2e6629968d8e54b5ed5da1812b7d9da9a38b66e1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 13
-EXTRAVERSION =-pre6
+EXTRAVERSION =
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
index e10cc2b4bdcaee72583abbba091dec418950a2f5..5021c216dce4c2b79be8ee6fc33e2a7e8f50dc95 100644 (file)
@@ -507,10 +507,9 @@ struct call_data_struct {
        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 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
  * 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 @@ asmlinkage void smp_call_function_interrupt(void)
 
        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);
+       }
 }
 
index 3f934db8bdea481a85c1621d27f46bd486bae310..00f28e63c493835eebbef87846608b84edaeba27 100644 (file)
@@ -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 @@ static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, str
        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 @@ static int i2ob_ioctl(struct inode *inode, struct file *file,
        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 @@ static int i2ob_release(struct inode *inode, struct file *file)
        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--;
@@ -1741,30 +1752,10 @@ void i2ob_del_device(struct i2o_controller *c, struct i2o_device *d)
        }
        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 @@ int i2o_block_init(void)
 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) {
index 311b535279cf709639fdc3c073b792a9091e7baf..db81acf15dd84c9d6acdf4edc7a99ec93d365b4e 100644 (file)
@@ -961,5 +961,6 @@ void cleanup_module(void)
 EXPORT_NO_SYMBOLS;
 MODULE_AUTHOR("Red Hat Software");
 MODULE_DESCRIPTION("I2O Configuration");
+MODULE_LICENSE("GPL");
 
 #endif
index 25360fdd2c0763155eeb0bff82fb1db2207728f6..55b1f722cfbbf6759a01de12db985db09a1dfcc9 100644 (file)
@@ -246,8 +246,8 @@ static void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c,
 
                 /* 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 @@ int i2o_delete_controller(struct i2o_controller *c)
                        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 @@ void i2o_run_queue(struct i2o_controller *c)
        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 @@ static int i2o_systab_send(struct i2o_controller *iop)
        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 @@ int i2o_post_outbound_messages(struct i2o_controller *c)
 
        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 @@ EXPORT_SYMBOL(i2o_get_class_name);
 
 MODULE_AUTHOR("Red Hat Software");
 MODULE_DESCRIPTION("I2O Core");
+MODULE_LICENSE("GPL");
+
 
 
 int init_module(void)
index 83bdf1c25328c294885df45729bacf66159f5b58..4c16aa854b9f1308113e76a294c2f462a1a0fe21 100644 (file)
@@ -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 @@ EXPORT_NO_SYMBOLS;
 
 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-)");
index 056b90fafdd003926c572b52cf6bb516534ef3de..880a234e831c21c5a2777e009e14782b44ec0177 100644 (file)
@@ -219,7 +219,11 @@ int __init i2o_pci_install(struct pci_dev *dev)
                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 @@ int __init i2o_pci_scan(void)
        {
                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 @@ EXPORT_SYMBOL(i2o_pci_core_detach);
 
 MODULE_AUTHOR("Red Hat Software");
 MODULE_DESCRIPTION("I2O PCI Interface");
+MODULE_LICENSE("GPL");
+
 
 #else
 void __init i2o_pci_init(void)
index e697bac19bf6058da96fcb54a108a770f580926e..ef820bfa55b0f4bbb398ea849377d7c21d9988cd 100644 (file)
@@ -299,14 +299,13 @@ static char* bus_strings[] =
 
 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 @@ int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len,
                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 @@ int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len,
        }
        
        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_remove_device(struct i2o_device *dev)
 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 @@ int __init i2o_proc_init(void)
 
 MODULE_AUTHOR("Deepak Saxena");
 MODULE_DESCRIPTION("I2O procfs Handler");
+MODULE_LICENSE("GPL");
 
 static void __exit i2o_proc_exit(void)
 {
index 93f27fb37aaec3204b7fc4e61448324aa3bcf857..cb59ae8f871f8c1c4d91a9ae0317dfd9cb1d2c4e 100644 (file)
@@ -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 @@ static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, stru
        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 @@ static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, stru
                }
                return;
        }
-                       
+       
+       prefetchw(&queue_depth);
+               
        
        /*
         *      Low byte is device status, next is adapter status,
@@ -548,6 +553,11 @@ int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
         
        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 @@ int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
        
        dprintk(("Real scsi messages.\n"));
 
-       c = hostdata->controller;
        
        /*
         *      Obtain an I2O message. Right now we _have_ to obtain one
@@ -906,6 +915,8 @@ int i2o_scsi_bios_param(Disk * disk, kdev_t dev, int *ip)
 }
 
 MODULE_AUTHOR("Red Hat Software");
+MODULE_LICENSE("GPL");
+
 
 static Scsi_Host_Template driver_template = I2OSCSI;
 
index 63846c348209754d414c1724c322764a019df691..a4ce9bac206003738eeb3bff791d9939176730fe 100644 (file)
@@ -78,9 +78,9 @@ static dpt_sig_S DPTI_sig = {
        {'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 @@ static int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout)
        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 @@ static int adpt_system_info(void *buffer)
 
 #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 ;
index 6ed4d261176e50cd525ba82fbb381782b5149268..5849b807501f26f6ee87d0c15d3eddbf9f70da4c 100644 (file)
  * 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 @@ static int prog_dmabuf(struct ymf_state *state, int rec)
        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 @@ static int prog_dmabuf(struct ymf_state *state, int rec)
         * 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 @@ ymf_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
        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 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
        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 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
                 * 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;
 }
index daa20cc6ba80137712be6930afd45e58944ba67f..92599976ed3cdb0a54acf077c0e6fbaa47d97fd5 100644 (file)
@@ -112,15 +112,16 @@ union bdflush_param {
                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 @@ static int grow_buffers(kdev_t dev, unsigned long block, int size)
        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;
 }
index 30cd82827ddd699eac96ada90f1de41878533cdd..fe14088a78e867a1c8412321e72ef88d313da262 100644 (file)
@@ -1159,6 +1159,7 @@ EXPORT_NO_SYMBOLS;
  */
 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");
index 73c5e08eac09fc0e4460fc38378a8f487f07b9b5..103a8176c4623eaef970cc544ebd764ec4c4dd1c 100644 (file)
@@ -214,7 +214,8 @@ enum bh_state_bits {
        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
index ef48a874ab1493617178e01e16105649b1b662a3..5047591f99fb49e070796841a8fb0a396c6529d0 100644 (file)
@@ -26,7 +26,7 @@ static inline void lock_buffer(struct buffer_head * bh)
                __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
index 81190ca013839436df091b7ff49dfebdbf98d63c..c94d22c727dbc5ea2fc14fb14f062540eb7fe467 100644 (file)
@@ -279,6 +279,7 @@ typedef struct page {
 #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 @@ typedef struct page {
 #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 @@ static inline void set_page_dirty(struct page * page)
  * 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 @@ extern struct page *filemap_nopage(struct vm_area_struct *, unsigned long, int);
 #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 */
index ae2cffd45ba0ca54fe5aa2966cf5c1d6c64f7efd..efa8638d612b8fc42b4cc1ce1b9feca14b54c51a 100644 (file)
@@ -24,7 +24,7 @@ typedef struct kmem_cache_s kmem_cache_t;
 #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().
index e8268cb67b74ab62134c9101522262f3618e08dd..006add2a9e709735c1bd57a4a3c53229308adc89 100644 (file)
@@ -102,15 +102,13 @@ extern void FASTCALL(__lru_cache_del(struct page *));
 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 *);
index 2832f6e13fbe0635ca660cf0e2012475ab202f91..7fb4165cedac9c2295d3f07e832a65bf14867252 100644 (file)
@@ -149,28 +149,21 @@ static inline int has_stopped_jobs(int pgrp)
 }
 
 /*
- * 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);
                }
        }
index b6c75572fe100c96475893a5817cfd06fe058749..dce6c792fd84ec91bc76f58796f110a1546664d1 100644 (file)
@@ -327,7 +327,6 @@ struct page *alloc_bounce_page (void)
        struct list_head *tmp;
        struct page *page;
 
-repeat_alloc:
        page = alloc_page(GFP_NOHIGHIO);
        if (page)
                return page;
@@ -337,6 +336,7 @@ repeat_alloc:
         */
        wakeup_bdflush();
 
+repeat_alloc:
        /*
         * Try to allocate from the emergency pool.
         */
@@ -365,7 +365,6 @@ struct buffer_head *alloc_bounce_bh (void)
        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 @@ repeat_alloc:
         */
        wakeup_bdflush();
 
+repeat_alloc:
        /*
         * Try to allocate from the emergency pool.
         */
index d1d69e6976b09938a2ddc08de83f4eb59c949222..3c7871dda7b9dec7ac05962b5ee2d3cea82ceb74 100644 (file)
@@ -242,7 +242,7 @@ static struct page * balance_classzone(zone_t * classzone, unsigned int gfp_mask
        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 @@ unsigned int nr_free_buffer_pages (void)
 {
        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 @@ unsigned int nr_free_highpages (void)
 }
 #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 @@ void show_free_areas_core(pg_data_t *pgdat)
                        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 @@ void show_free_areas_core(pg_data_t *pgdat)
                        }
                        spin_unlock_irqrestore(&zone->lock, flags);
                }
-               printk("= %lukB)\n", total * (PAGE_SIZE>>10));
+               printk("= %lukB)\n", K(total));
        }
 
 #ifdef SWAP_CACHE_INFO
index e7e544b3b93801ce991612272e9fd95a33469f04..24592571d76fb988c3feee66590c7d70e7c11362 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -48,7 +48,7 @@ pager_daemon_t pager_daemon = {
  * 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 @@ void deactivate_page(struct page * page)
 /*
  * 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);
index 412a2f7694d7eb1d99b158028c4bf9f0526e5d2d..555e4ea0f740cd56939da99e4744514e0b566c54 100644 (file)
@@ -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 @@ static inline int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct*
        /* 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 @@ drop_pte:
 }
 
 /* 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 @@ static inline int swap_out_pmd(struct mm_struct * mm, struct vm_area_struct * vm
                        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 @@ static inline int swap_out_pmd(struct mm_struct * mm, struct vm_area_struct * vm
 }
 
 /* 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 @@ static inline int swap_out_pgd(struct mm_struct * mm, struct vm_area_struct * vm
                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 @@ static inline int swap_out_pgd(struct mm_struct * mm, struct vm_area_struct * vm
 }
 
 /* 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 @@ static inline int swap_out_vma(struct mm_struct * mm, struct vm_area_struct * vm
        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 @@ struct mm_struct *swap_mm = &init_mm;
 /*
  * 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 @@ static inline int swap_out_mm(struct mm_struct * mm, int count, int * mmcounter)
                        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 @@ out_unlock:
        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 @@ static int swap_out(unsigned int priority, unsigned int gfp_mask, int nr_pages)
                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 @@ empty:
        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 @@ static int shrink_cache(int nr_pages, int max_scan, unsigned int gfp_mask)
 
                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 @@ static int shrink_cache(int nr_pages, int max_scan, unsigned int gfp_mask)
                        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 @@ static int shrink_cache(int nr_pages, int max_scan, unsigned int gfp_mask)
                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 @@ static void refill_inactive(int nr_pages)
        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 @@ static int shrink_caches(int priority, unsigned int gfp_mask, int nr_pages)
        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 @@ static int shrink_caches(int priority, unsigned int gfp_mask, int nr_pages)
        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 @@ static int kswapd_balance_pgdat(pg_data_t * pgdat)
                        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);