diff -urN 2.4.4pre6/include/linux/pagemap.h swapcachelookup/include/linux/pagemap.h --- 2.4.4pre6/include/linux/pagemap.h Tue Apr 24 14:01:18 2001 +++ swapcachelookup/include/linux/pagemap.h Tue Apr 24 16:23:52 2001 @@ -77,7 +77,12 @@ unsigned long index, struct page **hash); extern void lock_page(struct page *page); #define find_lock_page(mapping, index) \ - __find_lock_page(mapping, index, page_hash(mapping, index)) + __find_lock_page(mapping, index, page_hash(mapping, index)) + +extern struct page * __find_get_swapcache_page (int wait, struct address_space * mapping, + unsigned long index, struct page **hash); +#define find_get_swapcache_page(wait, mapping, index) \ + __find_get_swapcache_page(wait, mapping, index, page_hash(mapping, index)) extern void __add_page_to_hash_queue(struct page * page, struct page **p); diff -urN 2.4.4pre6/include/linux/swap.h swapcachelookup/include/linux/swap.h --- 2.4.4pre6/include/linux/swap.h Tue Apr 24 06:15:40 2001 +++ swapcachelookup/include/linux/swap.h Tue Apr 24 16:23:52 2001 @@ -120,7 +120,7 @@ extern void show_swap_cache_info(void); extern void add_to_swap_cache(struct page *, swp_entry_t); extern int swap_check_entry(unsigned long); -extern struct page * lookup_swap_cache(swp_entry_t); +extern struct page * lookup_swap_cache(swp_entry_t, int); extern struct page * read_swap_cache_async(swp_entry_t, int); #define read_swap_cache(entry) read_swap_cache_async(entry, 1); diff -urN 2.4.4pre6/mm/filemap.c swapcachelookup/mm/filemap.c --- 2.4.4pre6/mm/filemap.c Sat Apr 21 20:04:24 2001 +++ swapcachelookup/mm/filemap.c Tue Apr 24 16:23:52 2001 @@ -678,6 +678,43 @@ } /* + * Find a swapcache page (and get a reference) or return NULL. + * The SwapCache check is protected by the pagecache lock. + */ +struct page * __find_get_swapcache_page(int wait, struct address_space *mapping, + unsigned long offset, struct page **hash) +{ + struct page *page; + + /* + * We need the LRU lock to protect against page_launder(). + */ +repeat: + spin_lock(&pagecache_lock); + page = __find_page_nolock(mapping, offset, *hash); + if (page) { + spin_lock(&pagemap_lru_lock); + if (PageSwapCache(page)) { + page_cache_get(page); + if (!Page_Uptodate(page) && PageLocked(page) && wait) { + spin_unlock(&pagemap_lru_lock); + spin_unlock(&pagecache_lock); + ___wait_on_page(page); + page_cache_release(page); + goto repeat; + } + if (wait && (!Page_Uptodate(page) && PageLocked(page))) + printk(KERN_ERR "hm: page not uptodate in __find_get_swapcache_page()? page flags: %08lx\n", page->flags); + } else + page = NULL; + spin_unlock(&pagemap_lru_lock); + } + spin_unlock(&pagecache_lock); + + return page; +} + +/* * Same as the above, but lock the page too, verifying that * it's still valid once we own it. */ diff -urN 2.4.4pre6/mm/memory.c swapcachelookup/mm/memory.c --- 2.4.4pre6/mm/memory.c Sat Apr 21 20:04:24 2001 +++ swapcachelookup/mm/memory.c Tue Apr 24 16:23:52 2001 @@ -1059,7 +1059,7 @@ pte_t pte; spin_unlock(&mm->page_table_lock); - page = lookup_swap_cache(entry); + page = lookup_swap_cache(entry, 1); if (!page) { lock_kernel(); swapin_readahead(entry); diff -urN 2.4.4pre6/mm/shmem.c swapcachelookup/mm/shmem.c --- 2.4.4pre6/mm/shmem.c Sat Apr 21 20:04:24 2001 +++ swapcachelookup/mm/shmem.c Tue Apr 24 16:23:52 2001 @@ -123,7 +123,7 @@ entry = *ptr; *ptr = (swp_entry_t){0}; freed++; - if ((page = lookup_swap_cache(entry)) != NULL) { + if ((page = lookup_swap_cache(entry, 1)) != NULL) { delete_from_swap_cache(page); page_cache_release(page); } diff -urN 2.4.4pre6/mm/swap_state.c swapcachelookup/mm/swap_state.c --- 2.4.4pre6/mm/swap_state.c Sat Apr 21 20:04:24 2001 +++ swapcachelookup/mm/swap_state.c Tue Apr 24 16:23:52 2001 @@ -152,7 +152,7 @@ * lock before returning. */ -struct page * lookup_swap_cache(swp_entry_t entry) +struct page * lookup_swap_cache(swp_entry_t entry, int wait) { struct page *found; @@ -163,37 +163,18 @@ /* * Right now the pagecache is 32-bit only. But it's a 32 bit index. =) */ -repeat: - found = find_lock_page(&swapper_space, entry.val); + found = find_get_swapcache_page(wait, &swapper_space, entry.val); if (!found) return 0; - /* - * Though the "found" page was in the swap cache an instant - * earlier, it might have been removed by refill_inactive etc. - * Re search ... Since find_lock_page grabs a reference on - * the page, it can not be reused for anything else, namely - * it can not be associated with another swaphandle, so it - * is enough to check whether the page is still in the scache. - */ - if (!PageSwapCache(found)) { - UnlockPage(found); - page_cache_release(found); - goto repeat; - } + if (!PageSwapCache(found)) + BUG(); if (found->mapping != &swapper_space) - goto out_bad; + BUG(); #ifdef SWAP_CACHE_INFO swap_cache_find_success++; #endif - UnlockPage(found); return found; } - -out_bad: - printk (KERN_ERR "VM: Found a non-swapper swap page!\n"); - UnlockPage(found); - page_cache_release(found); - return 0; } /* @@ -218,7 +199,7 @@ /* * Look for the page in the swap cache. */ - found_page = lookup_swap_cache(entry); + found_page = lookup_swap_cache(entry, wait); if (found_page) goto out_free_swap; @@ -230,7 +211,7 @@ /* * Check the swap cache again, in case we stalled above. */ - found_page = lookup_swap_cache(entry); + found_page = lookup_swap_cache(entry, wait); if (found_page) goto out_free_page; /*