> 1. we take an extra reference on the page, how does that > affect the test for if the page is shared or not ? is_page_shared expects us to have our own reference to the page. > 2. we call delete_from_swap_cache with the pagemap_lru_lock > held, since this tries to grab the pagecache_lock we can > easily deadlock with the rest of the kernel (where the > locking order is opposite) You're right. Oversight on my part. Here is another version of the patch. > 3. there are no comments in the code explaining what this > suspicious-looking piece of code does ;) Oops... I sent out the wrong version of the patch the first time. This one has comments, promise. And it has one less bug. :) Rich
diff -rNu linux-2.4.1/include/linux/swap.h linux-2.4.1-paging-fix/include/linux/swap.h --- linux-2.4.1/include/linux/swap.h Tue Jan 30 02:24:56 2001 +++ linux-2.4.1-paging-fix/include/linux/swap.h Tue Mar 27 14:00:17 2001 @@ -69,6 +69,7 @@ FASTCALL(unsigned int nr_free_buffer_pages(void)); extern int nr_active_pages; extern int nr_inactive_dirty_pages; +extern int nr_swap_cache_pages; extern atomic_t nr_async_pages; extern struct address_space swapper_space; extern atomic_t page_cache_size; diff -rNu linux-2.4.1/mm/mmap.c linux-2.4.1-paging-fix/mm/mmap.c --- linux-2.4.1/mm/mmap.c Mon Jan 29 11:10:41 2001 +++ linux-2.4.1-paging-fix/mm/mmap.c Tue Mar 27 10:38:17 2001 @@ -63,6 +63,7 @@ free += atomic_read(&page_cache_size); free += nr_free_pages(); free += nr_swap_pages; + free += nr_swap_cache_pages; return free > pages; } diff -rNu linux-2.4.1/mm/swap_state.c linux-2.4.1-paging-fix/mm/swap_state.c --- linux-2.4.1/mm/swap_state.c Fri Dec 29 18:04:27 2000 +++ linux-2.4.1-paging-fix/mm/swap_state.c Tue Mar 27 10:41:04 2001 @@ -17,6 +17,8 @@ #include <asm/pgtable.h> +int nr_swap_cache_pages = 0; + static int swap_writepage(struct page *page) { rw_swap_page(WRITE, page, 0); @@ -58,6 +60,7 @@ #ifdef SWAP_CACHE_INFO swap_cache_add_total++; #endif + nr_swap_cache_pages++; if (!PageLocked(page)) BUG(); if (PageTestandSetSwapCache(page)) @@ -96,6 +99,7 @@ #ifdef SWAP_CACHE_INFO swap_cache_del_total++; #endif + nr_swap_cache_pages--; remove_from_swap_cache(page); swap_free(entry); } diff -rNu linux-2.4.1/mm/vmscan.c linux-2.4.1-paging-fix/mm/vmscan.c --- linux-2.4.1/mm/vmscan.c Mon Jan 15 15:36:49 2001 +++ linux-2.4.1-paging-fix/mm/vmscan.c Tue Mar 27 14:37:18 2001 @@ -394,6 +394,21 @@ return page; } +/** + * Short-circuits the dead swap cache page to prevent + * unnecessary disk IO + */ +static inline void delete_dead_swap_cache_page(struct page *page) { + if (block_flushpage(page, 0)) + lru_cache_del(page); + + ClearPageDirty(page); + spin_unlock(&pagemap_lru_lock); + __delete_from_swap_cache(page); + spin_lock(&pagemap_lru_lock); + page_cache_release(page); +} + /** * page_launder - clean dirty inactive pages, move to inactive_clean list * @gfp_mask: what operations we are allowed to do @@ -467,6 +482,24 @@ } /* + * Prevent a dead process's pages from being + * written to swap when no one else needs + * them. Lazy form of removing these pages + * at exit time. + */ + if (PageSwapCache(page)) { + page_cache_get(page); + if(!is_page_shared(page)) { + delete_dead_swap_cache_page(page); + + UnlockPage(page); + page_cache_release(page); + continue; + } + page_cache_release(page); + } + + /* * Dirty swap-cache page? Write it out if * last copy.. */ @@ -650,6 +683,24 @@ list_del(page_lru); nr_active_pages--; continue; + } + + /* + * Prevent a dead process's pages from being + * written to swap when no one else needs + * them. Lazy form of removing these pages + * at exit time. + */ + if (PageSwapCache(page)) { + page_cache_get(page); + if(!is_page_shared(page) && !TryLockPage(page)) { + delete_dead_swap_cache_page(page); + + UnlockPage(page); + page_cache_release(page); + continue; + } + page_cache_release(page); } /* Do aging on the pages. */