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--;