[LWN Logo]

Date:	Fri, 26 May 2000 18:57:45 -0300 (BRST)
From:	Rik van Riel <riel@conectiva.com.br>
To:	linux-kernel@vger.rutgers.edu
Subject: [PATCH] new VM sneak preview

Hi,

Here is a WORKING version of the deferred swapping & page aging
patch for 2.4.0-test1. It implements one part of the new VM
design (which we intend to finish before kernel 2.4). The code
changes are fairly minimal and system performance generally
seems to be better. However, YMMV ... and I'm very interested
in your milage ;)

The new design can be found here:
http://mail.nl.linux.org/linux-mm/2000-05/msg00418.html


This patch implements:
- deferred IO for pageout
- rudimentary page aging, a start of what we want
  for when we have an active list later

TODO:
- deferred swapping for other IO (file, shm)
- page aging for all pages
- inactive / laundry / cache queues
- ...

regards,

Rik
--
The Internet is not a network of computers. It is a network
of people. That is its real strength.

Wanna talk about the kernel?  irc.openprojects.net / #kernelnewbies
http://www.conectiva.com/		http://www.surriel.com/



--- linux-2.4.0-test1/mm/filemap.c.orig	Thu May 25 12:27:47 2000
+++ linux-2.4.0-test1/mm/filemap.c	Fri May 26 15:05:34 2000
@@ -264,7 +264,16 @@
 		page = list_entry(page_lru, struct page, lru);
 		list_del(page_lru);
 
-		if (PageTestandClearReferenced(page))
+		if (PageTestandClearReferenced(page)) {
+			page->age += 3;
+			if (page->age > 10)
+				page->age = 0;
+			goto dispose_continue;
+		}
+		if (page->age)
+			page->age--;
+
+		if (page->age)
 			goto dispose_continue;
 
 		count--;
@@ -317,28 +326,34 @@
 			goto cache_unlock_continue;
 
 		/*
+		 * Page is from a zone we don't care about.
+		 * Don't drop page cache entries in vain.
+		 */
+		if (page->zone->free_pages > page->zone->pages_high)
+			goto cache_unlock_continue;
+
+		/*
 		 * Is it a page swap page? If so, we want to
 		 * drop it if it is no longer used, even if it
 		 * were to be marked referenced..
 		 */
 		if (PageSwapCache(page)) {
-			spin_unlock(&pagecache_lock);
-			__delete_from_swap_cache(page);
-			goto made_inode_progress;
-		}	
-
-		/*
-		 * Page is from a zone we don't care about.
-		 * Don't drop page cache entries in vain.
-		 */
-		if (page->zone->free_pages > page->zone->pages_high)
+			if (!PageDirty(page)) {
+				spin_unlock(&pagecache_lock);
+				__delete_from_swap_cache(page);
+				goto made_inode_progress;
+			}
+			/* PageDeferswap -> we swap out the page now. */
+			if (gfp_mask & __GFP_IO)
+				goto async_swap;
 			goto cache_unlock_continue;
+		}
 
 		/* is it a page-cache page? */
 		if (page->mapping) {
 			if (!PageDirty(page) && !pgcache_under_min()) {
-				__remove_inode_page(page);
 				spin_unlock(&pagecache_lock);
+				__remove_inode_page(page);
 				goto made_inode_progress;
 			}
 			goto cache_unlock_continue;
@@ -351,6 +366,14 @@
 unlock_continue:
 		spin_lock(&pagemap_lru_lock);
 		UnlockPage(page);
+		page_cache_release(page);
+		goto dispose_continue;
+async_swap:
+		spin_unlock(&pagecache_lock);
+		/* Do NOT unlock the page ... that is done after IO. */
+		ClearPageDirty(page);
+		rw_swap_page(WRITE, page, 0);
+		spin_lock(&pagemap_lru_lock);
 		page_cache_release(page);
 dispose_continue:
 		list_add(page_lru, &lru_cache);
--- linux-2.4.0-test1/mm/page_alloc.c.orig	Thu May 25 12:27:47 2000
+++ linux-2.4.0-test1/mm/page_alloc.c	Fri May 26 17:23:00 2000
@@ -93,6 +93,8 @@
 		BUG();
 	if (PageDecrAfter(page))
 		BUG();
+	if (PageDirty(page))
+		BUG();
 
 	zone = page->zone;
 
--- linux-2.4.0-test1/mm/swap_state.c.orig	Thu May 25 12:27:47 2000
+++ linux-2.4.0-test1/mm/swap_state.c	Fri May 26 16:57:58 2000
@@ -73,6 +73,7 @@
 		PAGE_BUG(page);
 
 	PageClearSwapCache(page);
+	ClearPageDirty(page);
 	remove_inode_page(page);
 }
 
--- linux-2.4.0-test1/mm/vmscan.c.orig	Thu May 25 12:27:47 2000
+++ linux-2.4.0-test1/mm/vmscan.c	Fri May 26 16:55:03 2000
@@ -62,6 +62,10 @@
 		goto out_failed;
 	}
 
+	/* Can only do this if we age all active pages. */
+	if (PageActive(page) && page->age > 1)
+		goto out_failed;
+
 	if (TryLockPage(page))
 		goto out_failed;
 
@@ -74,6 +78,8 @@
 	 * memory, and we should just continue our scan.
 	 */
 	if (PageSwapCache(page)) {
+		if (pte_dirty(pte))
+			SetPageDirty(page);
 		entry.val = page->index;
 		swap_duplicate(entry);
 		set_pte(page_table, swp_entry_to_pte(entry));
@@ -181,7 +187,10 @@
 	vmlist_access_unlock(vma->vm_mm);
 
 	/* OK, do a physical asynchronous write to swap.  */
-	rw_swap_page(WRITE, page, 0);
+	// rw_swap_page(WRITE, page, 0);
+	/* Let shrink_mmap handle this swapout. */
+	SetPageDirty(page);
+	UnlockPage(page);
 
 out_free_success:
 	page_cache_release(page);
--- linux-2.4.0-test1/include/linux/mm.h.orig	Thu May 25 12:28:10 2000
+++ linux-2.4.0-test1/include/linux/mm.h	Fri May 26 17:52:30 2000
@@ -153,6 +153,7 @@
 	struct buffer_head * buffers;
 	unsigned long virtual; /* nonzero if kmapped */
 	struct zone_struct *zone;
+	unsigned int age;
 } mem_map_t;
 
 #define get_page(p)		atomic_inc(&(p)->count)
@@ -169,7 +170,7 @@
 #define PG_dirty		 4
 #define PG_decr_after		 5
 #define PG_unused_01		 6
-#define PG__unused_02		 7
+#define PG_active		 7
 #define PG_slab			 8
 #define PG_swap_cache		 9
 #define PG_skip			10
@@ -185,6 +186,7 @@
 #define ClearPageUptodate(page)	clear_bit(PG_uptodate, &(page)->flags)
 #define PageDirty(page)		test_bit(PG_dirty, &(page)->flags)
 #define SetPageDirty(page)	set_bit(PG_dirty, &(page)->flags)
+#define ClearPageDirty(page)	clear_bit(PG_dirty, &(page)->flags)
 #define PageLocked(page)	test_bit(PG_locked, &(page)->flags)
 #define LockPage(page)		set_bit(PG_locked, &(page)->flags)
 #define TryLockPage(page)	test_and_set_bit(PG_locked, &(page)->flags)
@@ -192,6 +194,9 @@
 					clear_bit(PG_locked, &(page)->flags); \
 					wake_up(&page->wait); \
 				} while (0)
+#define PageActive(page)	test_bit(PG_active, &(page)->flags)
+#define SetPageActive(page)	set_bit(PG_active, &(page)->flags)
+#define ClearPageActive(page)	clear_bit(PG_active, &(page)->flags)
 #define PageError(page)		test_bit(PG_error, &(page)->flags)
 #define SetPageError(page)	set_bit(PG_error, &(page)->flags)
 #define ClearPageError(page)	clear_bit(PG_error, &(page)->flags)
--- linux-2.4.0-test1/include/linux/swap.h.orig	Thu May 25 12:28:13 2000
+++ linux-2.4.0-test1/include/linux/swap.h	Fri May 26 16:54:41 2000
@@ -168,12 +168,15 @@
 	spin_lock(&pagemap_lru_lock);		\
 	list_add(&(page)->lru, &lru_cache);	\
 	nr_lru_pages++;				\
+	page->age = 2;				\
+	SetPageActive(page);			\
 	spin_unlock(&pagemap_lru_lock);		\
 } while (0)
 
 #define	__lru_cache_del(page)			\
 do {						\
 	list_del(&(page)->lru);			\
+	ClearPageActive(page);			\
 	nr_lru_pages--;				\
 } while (0)
 



-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/