[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] Reclaim orphaned swap pages



From what I can see of the patch vm_enough_memory will still fail causing
premature oom merely because those pages haven't been accounted for as
free.  The checking should probably be done in page_launder, too, to
prevent the write at that level.  Also, the page count might be two,
depending on if you have buffers.  The attached patch should work just
fine and remove these pages as quickly as possible.  I sent it out to the
kernel list on the 27th in response to Stephen Tweedie's point that exit
path deletion was slow, but I guess it belongs here.

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