diff -u --recursive --new-file linux-2.2.18-sunrpc/fs/nfs/write.c linux-2.2.18-mm/fs/nfs/write.c --- linux-2.2.18-sunrpc/fs/nfs/write.c Mon Nov 13 17:16:00 2000 +++ linux-2.2.18-mm/fs/nfs/write.c Thu Nov 16 15:30:37 2000 @@ -1129,7 +1129,6 @@ } } #endif - /* Update attributes as result of writeback. */ nfs_write_attributes(inode, resp->fattr); @@ -1286,6 +1285,7 @@ task->tk_pid, task->tk_status); nfs_write_attributes(inode, resp->fattr); + while (!list_empty(&data->pages)) { req = nfs_list_entry(data->pages.next); nfs_list_remove_request(req); diff -u --recursive --new-file linux-2.2.18-sunrpc/include/linux/mm.h linux-2.2.18-mm/include/linux/mm.h --- linux-2.2.18-sunrpc/include/linux/mm.h Mon Nov 13 17:16:15 2000 +++ linux-2.2.18-mm/include/linux/mm.h Mon Nov 13 17:24:48 2000 @@ -144,6 +144,7 @@ #define PG_Slab 9 #define PG_swap_cache 10 #define PG_skip 11 +#define PG_invalid 13 #define PG_reserved 31 /* Make it prettier to test the above... */ @@ -176,6 +177,13 @@ #define PageTestandClearSwapCache(page) \ (test_and_clear_bit(PG_swap_cache, &(page)->flags)) +#define SetPageInvalid(page) \ + set_bit(PG_invalid, &(page)->flags) +#define ClearPageInvalid(page) \ + clear_bit(PG_invalid, &(page)->flags) +#define PageInvalid(page) \ + test_bit(PG_invalid, &(page)->flags) + /* * Various page->flags bits: * @@ -317,6 +325,7 @@ /* filemap.c */ extern void remove_inode_page(struct page *); +extern void invalid_page_reap(struct page *); extern unsigned long page_unuse(struct page *); extern int shrink_mmap(int, int); extern void truncate_inode_pages(struct inode *, unsigned long); diff -u --recursive --new-file linux-2.2.18-sunrpc/include/linux/pagemap.h linux-2.2.18-mm/include/linux/pagemap.h --- linux-2.2.18-sunrpc/include/linux/pagemap.h Mon Nov 13 17:16:16 2000 +++ linux-2.2.18-mm/include/linux/pagemap.h Mon Nov 13 17:24:54 2000 @@ -31,7 +31,14 @@ #define page_cache_alloc() __get_free_page(GFP_USER) #define page_cache_free(x) free_page(x) -#define page_cache_release(x) __free_page(x) + +static inline void +page_cache_release(struct page *page) +{ + __free_page(page); + if (PageInvalid(page)) + invalid_page_reap(page); +} /* * From a kernel address, get the "struct page *" diff -u --recursive --new-file linux-2.2.18-sunrpc/kernel/ksyms.c linux-2.2.18-mm/kernel/ksyms.c --- linux-2.2.18-sunrpc/kernel/ksyms.c Mon Nov 13 17:16:18 2000 +++ linux-2.2.18-mm/kernel/ksyms.c Mon Nov 13 17:17:14 2000 @@ -157,6 +157,7 @@ EXPORT_SYMBOL(check_disk_change); EXPORT_SYMBOL(__invalidate_buffers); EXPORT_SYMBOL(invalidate_inodes); +EXPORT_SYMBOL(invalid_page_reap); EXPORT_SYMBOL(invalidate_inode_pages); EXPORT_SYMBOL(truncate_inode_pages); EXPORT_SYMBOL(fsync_dev); diff -u --recursive --new-file linux-2.2.18-sunrpc/mm/filemap.c linux-2.2.18-mm/mm/filemap.c --- linux-2.2.18-sunrpc/mm/filemap.c Mon Nov 13 17:16:19 2000 +++ linux-2.2.18-mm/mm/filemap.c Mon Nov 13 17:17:14 2000 @@ -65,6 +65,13 @@ return 0; } +void invalid_page_reap(struct page *page) +{ + if (!PageInvalid(page) || atomic_read(&page->count) != 1 || PageLocked(page)) + return; + remove_inode_page(page); +} + /* * Invalidate the pages of an inode, removing all pages that aren't * locked down (those are sure to be up-to-date anyway, so we shouldn't @@ -81,6 +88,11 @@ p = &page->next; continue; } + if (atomic_read(&page->count) != 1) { + SetPageInvalid(page); + p = &page->next; + continue; + } inode->i_nrpages--; if ((*p = page->next) != NULL) (*p)->prev = page->prev; @@ -88,6 +100,8 @@ page->prev = NULL; remove_page_from_hash_queue(page); page->inode = NULL; + if (PageInvalid(page)) + ClearPageInvalid(page); page_cache_release(page); continue; } @@ -120,6 +134,8 @@ page->prev = NULL; remove_page_from_hash_queue(page); page->inode = NULL; + if (PageInvalid(page)) + ClearPageInvalid(page); page_cache_release(page); continue; } @@ -141,6 +157,8 @@ { remove_page_from_hash_queue(page); remove_page_from_inode_queue(page); + if (PageInvalid(page)) + ClearPageInvalid(page); page_cache_release(page); }