Linus, The following patch changes swap_writepage() to try to do write clustering of phisically contiguous pages which are dirty and in the swapcache. Do you want to include it in 2.4? diff -Nur --exclude-from=exclude linux.orig/include/linux/mm.h linux/include/linux/mm.h --- linux.orig/include/linux/mm.h Thu Dec 21 04:34:19 2000 +++ linux/include/linux/mm.h Thu Dec 21 03:56:30 2000 @@ -451,6 +451,8 @@ extern int filemap_swapout(struct page *, struct file *); extern int filemap_sync(struct vm_area_struct *, unsigned long, size_t, unsigned int); extern struct page *filemap_nopage(struct vm_area_struct *, unsigned long, int); +extern inline struct page * ___find_page_nolock(struct address_space *, unsigned +long, struct page *); + /* * GFP bitmasks.. diff -Nur --exclude-from=exclude linux.orig/include/linux/swap.h linux/include/linux/swap.h --- linux.orig/include/linux/swap.h Thu Dec 21 04:34:19 2000 +++ linux/include/linux/swap.h Thu Dec 21 04:16:42 2000 @@ -166,6 +166,8 @@ extern unsigned long swap_cache_find_total; extern unsigned long swap_cache_find_success; #endif + +extern struct swap_info_struct swap_info[MAX_SWAPFILES]; /* * Work out if there are any other processes sharing this page, ignoring diff -Nur --exclude-from=exclude linux.orig/mm/filemap.c linux/mm/filemap.c --- linux.orig/mm/filemap.c Thu Dec 21 04:34:20 2000 +++ linux/mm/filemap.c Thu Dec 21 03:53:41 2000 @@ -242,7 +242,7 @@ spin_unlock(&pagecache_lock); } -static inline struct page * __find_page_nolock(struct address_space *mapping, unsigned long offset, struct page *page) +inline struct page * ___find_page_nolock(struct address_space *mapping, unsigned long +offset, struct page *page) { goto inside; @@ -250,12 +250,22 @@ page = page->next_hash; inside: if (!page) - goto not_found; + return NULL; if (page->mapping != mapping) continue; if (page->index == offset) break; } + return page; +} + +static inline struct page * __find_page_nolock(struct address_space *mapping, +unsigned long offset, struct page *page) +{ + page = ___find_page_nolock(mapping, offset, page); + + if(!page) + return NULL; + /* * Touching the page may move it to the active list. * If we end up with too few inactive pages, we wake @@ -264,7 +274,7 @@ age_page_up(page); if (inactive_shortage() > inactive_target / 2 && free_shortage()) wakeup_kswapd(0); -not_found: + return page; } diff -Nur --exclude-from=exclude linux.orig/mm/swap_state.c linux/mm/swap_state.c --- linux.orig/mm/swap_state.c Mon Dec 4 19:22:02 2000 +++ linux/mm/swap_state.c Thu Dec 21 04:23:47 2000 @@ -5,6 +5,8 @@ * Swap reorganised 29.12.95, Stephen Tweedie * * Rewritten to use page cache, (C) 1998 Stephen Tweedie + * + * 21/12/2000 Added swap write clustering. Marcelo Tosatti */ #include <linux/mm.h> @@ -17,9 +19,95 @@ #include <asm/pgtable.h> +static inline struct page * swap_page_dirty(unsigned long, unsigned long, struct +swap_info_struct *); + +#define SWAP_WRITE_CLUSTER (1 << page_cluster) + static int swap_writepage(struct page *page) { - rw_swap_page(WRITE, page, 0); + unsigned long page_offset, curr, offset, i, type; + struct swap_info_struct *swap; + swp_entry_t entry; + struct page *cpages[SWAP_WRITE_CLUSTER*2]; + int count, first; + + entry.val = page->index; + + type = SWP_TYPE(entry); + + swap = &swap_info[type]; + + /* If swap area is not a real device, do not try to write cluster. */ + if(!swap->swap_device) { + rw_swap_page(WRITE, page, 0); + return 0; + } + + page_offset = offset = SWP_OFFSET(entry); + cpages[SWAP_WRITE_CLUSTER] = page; + count = 1; + first = SWAP_WRITE_CLUSTER; + curr = 1; + + spin_lock(&pagecache_lock); + swap_device_lock(swap); + + /* + * Search for clusterable dirty swap pages. + */ + + while (count < SWAP_WRITE_CLUSTER) { + struct page *p = NULL; + + if(offset <= 0) + break; + + offset = page_offset - curr; + p = swap_page_dirty(offset, type, swap); + + if(!p) + break; + + cpages[--first] = p; + + ClearPageDirty(p); + curr++; + count++; + } + + curr = 1; + + while (count < SWAP_WRITE_CLUSTER) { + struct page *p = NULL; + offset = page_offset + curr; + + if(offset >= swap->max) + break; + + p = swap_page_dirty(offset, type, swap); + if(!p) + break; + + cpages[first + count] = p; + ClearPageDirty(p); + curr++; + count++; + } + + swap_device_unlock(swap); + spin_unlock(&pagecache_lock); + + /* Now write out everything we were able to cluster */ + + for(i=0; i<count; i++) { + int pos = first + i; + rw_swap_page(WRITE, cpages[pos], 0); + + /* If the page is a clustered one, decrement its counter */ + if(pos != SWAP_WRITE_CLUSTER) + page_cache_release(cpages[pos]); + } + return 0; } @@ -36,6 +124,43 @@ 0, /* nrpages */ &swap_aops, }; + +static inline struct page * swap_page_dirty(unsigned long offset, unsigned long type, + struct swap_info_struct *swapdev) +{ + struct page *page, **hash; + swp_entry_t entry; + unsigned long index; + + entry = SWP_ENTRY(type, offset); + + index = entry.val; + + if(!swapdev->swap_map[offset]) + return NULL; + + if(swapdev->swap_map[offset] == SWAP_MAP_BAD) + return NULL; + + hash = page_hash(&swapper_space, index); + + page = ___find_page_nolock(&swapper_space, index, *hash); + + if(!page) + return NULL; + + if(TryLockPage(page)) + return NULL; + + page_cache_get(page); + + if(PageDirty(page) && PageSwapCache(page)) + return page; + + UnlockPage(page); + page_cache_release(page); + return NULL; +} #ifdef SWAP_CACHE_INFO unsigned long swap_cache_add_total; - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] Please read the FAQ at http://www.tux.org/lkml/