> 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. */

Reply via email to