diff -urN linux-2.0.31-linus/fs/buffer.c linux/fs/buffer.c
--- linux-2.0.31-linus/fs/buffer.c      Mon Aug 18 13:58:51 1997
+++ linux/fs/buffer.c   Fri Aug 22 11:54:58 1997
@@ -543,14 +543,11 @@
static inline int can_reclaim(struct buffer_head *bh, int size)
{
       if (bh->b_count ||
-           buffer_protected(bh) || buffer_locked(bh))
+           buffer_protected(bh) ||
+           buffer_locked(bh) ||
+           mem_map[MAP_NR((unsigned long) bh->b_data)].count != 1 ||
+           buffer_dirty(bh))
               return 0;
-
-       if (mem_map[MAP_NR((unsigned long) bh->b_data)].count != 1 ||
-           buffer_dirty(bh)) {
-               /* WSH: don't attempt to refile here! */
-               return 0;
-       }

       if (bh->b_size != size)
               return 0;
@@ -559,13 +556,15 @@
}

/* find a candidate buffer to be reclaimed */
-static struct buffer_head *find_candidate(struct buffer_head *list,int *list_len,int size)
+static struct buffer_head *find_candidate(struct buffer_head *bh,
+                                         int *list_len, int size)
{
-       struct buffer_head *bh;
+       int lookahead = 42;
+
+       if (!bh)
+               goto no_candidate;

-       for (bh = list;
-            bh && (*list_len) > 0;
-            bh = bh->b_next_free, (*list_len)--) {
+       for (; (*list_len) > 0; bh = bh->b_next_free, (*list_len)--) {
               if (size != bh->b_size) {
                       /* this provides a mechanism for freeing blocks
                          of other sizes, this is necessary now that we
@@ -573,23 +572,21 @@
                       try_to_free_buffer(bh,&bh,1);
                       if (!bh)
                               break;
+                       lookahead = 42;
                       continue;
               }
-
-               if (buffer_locked(bh) &&
-                   (bh->b_list == BUF_LOCKED || bh->b_list == BUF_LOCKED1)) {
-                       /* Buffers are written in the order they are placed
-                          on the locked list. If we encounter a locked
-                          buffer here, this means that the rest of them
-                          are also locked */
-                       (*list_len) = 0;
-                       return NULL;
+               else if (buffer_locked(bh) &&
+                        (bh->b_list == BUF_LOCKED || bh->b_list == BUF_LOCKED1)) {
+                       if (lookahead--) {
+                               (*list_len) = 0;
+                               goto no_candidate;
+                       }
               }
-
-               if (can_reclaim(bh,size))
-                   return bh;
+               else if (can_reclaim(bh,size))
+                       return bh;
       }

+no_candidate:
       return NULL;
}

@@ -662,6 +659,11 @@
               }
               goto repeat;
       }
+
+       /* Dirty buffers should not overtake, wakeup_bdflush(1) calls
+          bdflush and sleeps, therefore kswapd does his important work. */
+       if (nr_buffers_type[BUF_DIRTY] > nr_buffers * bdf_prm.b_un.nfract/100)
+               wakeup_bdflush(1);

       /* Too bad, that was not enough. Try a little harder to grow some. */

@@ -672,7 +674,6 @@
               };
       }

-#if 0
       /*
        * In order to protect our reserved pages,
        * return now if we got any buffers.
@@ -681,10 +682,8 @@
               return;

       /* and repeat until we find something good */
-       if (!grow_buffers(GFP_ATOMIC, size))
+       if (!grow_buffers(GFP_BUFFER, size))
               wakeup_bdflush(1);
-#endif
-       wakeup_bdflush(1);

       /* decrease needed even if there is no success */
       needed -= PAGE_SIZE;
@@ -1717,7 +1716,7 @@
                * dirty buffers, then make the next write to a
                * loop device to be a blocking write.
                * This lets us block--which we _must_ do! */
-               if (ndirty == 0 && nr_buffers_type[BUF_DIRTY] > 0) {
+               if (ndirty == 0 && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) {
                       wrta_cmd = WRITE;
                       continue;
               }
@@ -1725,7 +1724,7 @@

               /* If there are still a lot of dirty buffers around, skip the sleep
                  and flush some more */
-               if(nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) {
+               if(ndirty == 0 || nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) {
                       wake_up(&bdflush_done);
                       current->signal = 0;
                       interruptible_sleep_on(&bdflush_wait);
diff -urN linux-2.0.31-linus/include/linux/mm.h linux/include/linux/mm.h
--- linux-2.0.31-linus/include/linux/mm.h       Mon Jul 21 21:52:45 1997
+++ linux/include/linux/mm.h    Fri Aug 22 12:05:00 1997
@@ -295,7 +295,7 @@

/* filemap.c */
extern unsigned long page_unuse(unsigned long);
-extern int shrink_mmap(int, int);
+extern int shrink_mmap(int, int, int);
extern void truncate_inode_pages(struct inode *, unsigned long);

#define GFP_BUFFER     0x00
diff -urN linux-2.0.31-linus/mm/filemap.c linux/mm/filemap.c
--- linux-2.0.31-linus/mm/filemap.c     Mon Aug 18 13:58:55 1997
+++ linux/mm/filemap.c  Fri Aug 22 11:37:00 1997
@@ -114,7 +114,7 @@
       }
}

-int shrink_mmap(int priority, int dma)
+int shrink_mmap(int priority, int dma, int can_do_io)
{
       static int clock = 0;
       struct page * page;
@@ -174,7 +174,7 @@
                               }

                               /* is it a buffer cache page? */
-                               if (bh && try_to_free_buffer(bh, &bh, 6))
+                               if (can_do_io && bh && try_to_free_buffer(bh, &bh, 6))
                                       return 1;
                               break;

diff -urN linux-2.0.31-linus/mm/page_alloc.c linux/mm/page_alloc.c
--- linux-2.0.31-linus/mm/page_alloc.c  Mon Aug 18 13:58:55 1997
+++ linux/mm/page_alloc.c       Fri Aug 22 11:37:00 1997
@@ -214,7 +214,7 @@
               return 0;
       }
       restore_flags(flags);
-       if (priority != GFP_BUFFER && try_to_free_page(priority, dma, 1))
+       if (try_to_free_page(priority, dma, 1))
               goto repeat;
       return 0;
}
diff -urN linux-2.0.31-linus/mm/vmscan.c linux/mm/vmscan.c
--- linux-2.0.31-linus/mm/vmscan.c      Mon Aug 18 13:58:55 1997
+++ linux/mm/vmscan.c   Tue Aug 26 10:27:39 1997
@@ -31,7 +31,7 @@
/*
 * To check memory consuming code elsewhere set this to 1
 */
-#define MM_DEBUG 0
+/* #define MM_DEBUG */

/*
 * When are we next due for a page scan?
@@ -80,7 +80,7 @@
 * have died while we slept).
 */
static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma,
-       unsigned long address, pte_t * page_table, int dma, int wait)
+       unsigned long address, pte_t * page_table, int dma, int wait, int can_do_io)
{
       pte_t pte;
       unsigned long entry;
@@ -112,6 +112,8 @@
       if (page_map->age)
               return 0;
       if (pte_dirty(pte)) {
+               if(!can_do_io)
+                       return 0;
               if (vma->vm_ops && vma->vm_ops->swapout) {
                       pid_t pid = tsk->pid;
                       vma->vm_mm->rss--;
@@ -169,7 +171,8 @@
 */

static inline int swap_out_pmd(struct task_struct * tsk, struct vm_area_struct * vma,
-       pmd_t *dir, unsigned long address, unsigned long end, int dma, int wait)
+       pmd_t *dir, unsigned long address, unsigned long end, int dma, int wait,
+       int can_do_io)
{
       pte_t * pte;
       unsigned long pmd_end;
@@ -191,7 +194,8 @@
       do {
               int result;
               tsk->swap_address = address + PAGE_SIZE;
-               result = try_to_swap_out(tsk, vma, address, pte, dma, wait);
+               result = try_to_swap_out(tsk, vma, address, pte, dma, wait,
+                                        can_do_io);
               if (result)
                       return result;
               address += PAGE_SIZE;
@@ -201,7 +205,8 @@
}

static inline int swap_out_pgd(struct task_struct * tsk, struct vm_area_struct * vma,
-       pgd_t *dir, unsigned long address, unsigned long end, int dma, int wait)
+       pgd_t *dir, unsigned long address, unsigned long end, int dma, int wait,
+       int can_do_io)
{
       pmd_t * pmd;
       unsigned long pgd_end;
@@ -221,7 +226,8 @@
               end = pgd_end;

       do {
-               int result = swap_out_pmd(tsk, vma, pmd, address, end, dma, wait);
+               int result = swap_out_pmd(tsk, vma, pmd, address, end, dma, wait,
+                                         can_do_io);
               if (result)
                       return result;
               address = (address + PMD_SIZE) & PMD_MASK;
@@ -231,7 +237,7 @@
}

static int swap_out_vma(struct task_struct * tsk, struct vm_area_struct * vma,
-       pgd_t *pgdir, unsigned long start, int dma, int wait)
+       pgd_t *pgdir, unsigned long start, int dma, int wait, int can_do_io)
{
       unsigned long end;

@@ -242,7 +248,8 @@

       end = vma->vm_end;
       while (start < end) {
-               int result = swap_out_pgd(tsk, vma, pgdir, start, end, dma, wait);
+               int result = swap_out_pgd(tsk, vma, pgdir, start, end, dma, wait,
+                                         can_do_io);
               if (result)
                       return result;
               start = (start + PGDIR_SIZE) & PGDIR_MASK;
@@ -251,7 +258,7 @@
       return 0;
}

-static int swap_out_process(struct task_struct * p, int dma, int wait)
+static int swap_out_process(struct task_struct * p, int dma, int wait, int can_do_io)
{
       unsigned long address;
       struct vm_area_struct* vma;
@@ -272,7 +279,8 @@
               address = vma->vm_start;

       for (;;) {
-               int result = swap_out_vma(p, vma, pgd_offset(p->mm, address), address, dma, wait);
+               int result = swap_out_vma(p, vma, pgd_offset(p->mm, address), address, dma, wait,
+                                         can_do_io);
               if (result)
                       return result;
               vma = vma->vm_next;
@@ -284,7 +292,7 @@
       return 0;
}

-static int swap_out(unsigned int priority, int dma, int wait)
+static int swap_out(unsigned int priority, int dma, int wait, int can_do_io)
{
       static int swap_task;
       int loop, counter, shfrv;
@@ -357,7 +365,7 @@
               }
               if (!--p->swap_cnt)
                       swap_task++;
-               switch (swap_out_process(p, dma, wait)) {
+               switch (swap_out_process(p, dma, wait, can_do_io)) {
                       case 0:
                               if (p->state == TASK_STOPPED)
                                       /* Stopped task occupy nonused ram */
@@ -391,24 +399,30 @@
{
       static int state = 0;
       int i=6;
-       int stop;
+       int stop, can_do_io;

       /* we don't try as hard if we're not waiting.. */
       stop = 3;
+       can_do_io = 1;
       if (wait)
               stop = 0;
+       if (priority == GFP_BUFFER) {
+               /* bdflush() should do the rest if we fail */
+               stop = 3;
+               can_do_io = 0;
+       }
       switch (state) {
               do {
               case 0:
-                       if (shrink_mmap(i, dma))
+                       if (shrink_mmap(i, dma, can_do_io))
                               return 1;
                       state = 1;
               case 1:
-                       if (shm_swap(i, dma))
+                       if (can_do_io && shm_swap(i, dma))
                               return 1;
                       state = 2;
               default:
-                       if (swap_out(i, dma, wait))
+                       if (swap_out(i, dma, wait, can_do_io))
                               return 1;
                       state = 0;
               i--;