Subject: My latest page scanner patch
To: None <tech-kern@netbsd.org>
From: Jason R Thorpe <thorpej@zembu.com>
List: tech-kern
Date: 01/26/2001 11:34:15
Folks..

Here is my latest page scanner patch.  Note that I'm still debating
whether or not to clear_reference or actually deactivate the pages
in the aobj/map "clean" path, tho I'm leaning towards deactivate (they
go on the end of the list, so other references won't be penalized unless
there's a free page shortage).

I would really appreciate it if people would "cvs update" their
sys/uvm directory and try this patch, and report to me any change
in behavior (positive or negative) on their systems.

-- 
        -- Jason R. Thorpe <thorpej@zembu.com>

Index: uvm_anon.c
===================================================================
RCS file: /cvsroot/syssrc/sys/uvm/uvm_anon.c,v
retrieving revision 1.13
diff -c -r1.13 uvm_anon.c
*** uvm_anon.c	2001/01/23 02:27:39	1.13
--- uvm_anon.c	2001/01/26 19:18:54
***************
*** 526,532 ****
  	 */
  
  	pmap_clear_reference(pg);
- 	pmap_page_protect(pg, VM_PROT_NONE);
  	uvm_lock_pageq();
  	uvm_pagedeactivate(pg);
  	uvm_unlock_pageq();
--- 526,531 ----
Index: uvm_aobj.c
===================================================================
RCS file: /cvsroot/syssrc/sys/uvm/uvm_aobj.c,v
retrieving revision 1.37
diff -c -r1.37 uvm_aobj.c
*** uvm_aobj.c	2000/11/25 06:27:59	1.37
--- uvm_aobj.c	2001/01/26 19:18:54
***************
*** 882,892 ****
  			    pp->wire_count != 0)
  				continue;
  
! 			/* zap all mappings for the page. */
! 			pmap_page_protect(pp, VM_PROT_NONE);
! 
  			/* ...and deactivate the page. */
  			uvm_pagedeactivate(pp);
  
  			continue;
  
--- 882,900 ----
  			    pp->wire_count != 0)
  				continue;
  
! #if 1
! 			/*
! 			 * simply clear the reference to the page.
! 			 * the page will remain on the active queue,
! 			 * and if nothing references it by the next
! 			 * time the scanner runs, it will be deactivated
! 			 * at that time.
! 			 */
! 			pmap_clear_reference(pp);
! #else
  			/* ...and deactivate the page. */
  			uvm_pagedeactivate(pp);
+ #endif
  
  			continue;
  
***************
*** 1543,1549 ****
  	 * deactivate the page (to put it on a page queue).
  	 */
  	pmap_clear_reference(pg);
- 	pmap_page_protect(pg, VM_PROT_NONE);
  	uvm_lock_pageq();
  	uvm_pagedeactivate(pg);
  	uvm_unlock_pageq();
--- 1551,1556 ----
Index: uvm_fault.c
===================================================================
RCS file: /cvsroot/syssrc/sys/uvm/uvm_fault.c,v
retrieving revision 1.54
diff -c -r1.54 uvm_fault.c
*** uvm_fault.c	2001/01/23 02:27:39	1.54
--- uvm_fault.c	2001/01/26 19:18:56
***************
*** 205,211 ****
  		if (pg && (pg->flags & PG_BUSY) == 0 && pg->loan_count == 0) {
  			uvm_lock_pageq();
  			if (pg->wire_count == 0) {
! 				pmap_page_protect(pg, VM_PROT_NONE);
  				uvm_pagedeactivate(pg);
  			}
  			uvm_unlock_pageq();
--- 205,211 ----
  		if (pg && (pg->flags & PG_BUSY) == 0 && pg->loan_count == 0) {
  			uvm_lock_pageq();
  			if (pg->wire_count == 0) {
! 				pmap_clear_reference(pg);
  				uvm_pagedeactivate(pg);
  			}
  			uvm_unlock_pageq();
Index: uvm_map.c
===================================================================
RCS file: /cvsroot/syssrc/sys/uvm/uvm_map.c,v
retrieving revision 1.88
diff -c -r1.88 uvm_map.c
*** uvm_map.c	2001/01/14 02:10:01	1.88
--- uvm_map.c	2001/01/26 19:18:58
***************
*** 2566,2576 ****
  				}
  				KASSERT(pg->uanon == anon);
  
! 				/* zap all mappings for the page. */
! 				pmap_page_protect(pg, VM_PROT_NONE);
! 
  				/* ...and deactivate the page. */
  				uvm_pagedeactivate(pg);
  
  				uvm_unlock_pageq();
  				simple_unlock(&anon->an_lock);
--- 2566,2584 ----
  				}
  				KASSERT(pg->uanon == anon);
  
! #if 1
! 				/*
! 				 * simply clear the reference to the page.
! 				 * the page will remain on the active queue,
! 				 * and if nothing references it by the next
! 				 * time the scanner runs, it will be de-
! 				 * activated at that time.
! 				 */
! 				pmap_clear_reference(pg);
! #else
  				/* ...and deactivate the page. */
  				uvm_pagedeactivate(pg);
+ #endif
  
  				uvm_unlock_pageq();
  				simple_unlock(&anon->an_lock);
Index: uvm_page_i.h
===================================================================
RCS file: /cvsroot/syssrc/sys/uvm/uvm_page_i.h,v
retrieving revision 1.15
diff -c -r1.15 uvm_page_i.h
*** uvm_page_i.h	2001/01/14 02:10:02	1.15
--- uvm_page_i.h	2001/01/26 19:18:59
***************
*** 193,203 ****
  }
  
  /*
!  * uvm_pagedeactivate: deactivate page -- no pmaps have access to page
   *
   * => caller must lock page queues
   * => caller must check to make sure page is not wired
   * => object that page belongs to must be locked (so we can adjust pg->flags)
   */
  
  PAGE_INLINE void
--- 193,204 ----
  }
  
  /*
!  * uvm_pagedeactivate: deactivate page
   *
   * => caller must lock page queues
   * => caller must check to make sure page is not wired
   * => object that page belongs to must be locked (so we can adjust pg->flags)
+  * => caller must clear the reference on the page before calling
   */
  
  PAGE_INLINE void
***************
*** 217,223 ****
  			TAILQ_INSERT_TAIL(&uvm.page_inactive_obj, pg, pageq);
  		pg->pqflags |= PQ_INACTIVE;
  		uvmexp.inactive++;
! 		pmap_clear_reference(pg);
  		if (pmap_is_modified(pg))
  			pg->flags &= ~PG_CLEAN;
  	}
--- 218,231 ----
  			TAILQ_INSERT_TAIL(&uvm.page_inactive_obj, pg, pageq);
  		pg->pqflags |= PQ_INACTIVE;
  		uvmexp.inactive++;
! 
! 		/* XXX this probably isn't even necessary. */
! 		/*
! 		 * update the "clean" bit.  this isn't 100%
! 		 * accurate, and doesn't have to be.  we'll
! 		 * re-sync it after we zap all mappings when
! 		 * scanning the inactive list.
! 		 */
  		if (pmap_is_modified(pg))
  			pg->flags &= ~PG_CLEAN;
  	}
Index: uvm_pager.c
===================================================================
RCS file: /cvsroot/syssrc/sys/uvm/uvm_pager.c,v
retrieving revision 1.38
diff -c -r1.38 uvm_pager.c
*** uvm_pager.c	2000/12/09 23:26:27	1.38
--- uvm_pager.c	2001/01/26 19:18:59
***************
*** 315,325 ****
  	/*
  	 * attempt to cluster around the left [backward], and then 
  	 * the right side [forward].    
- 	 *
- 	 * note that for inactive pages (pages that have been deactivated)
- 	 * there are no valid mappings and PG_CLEAN should be up to date.
- 	 * [i.e. there is no need to query the pmap with pmap_is_modified
- 	 * since there are no mappings].
  	 */
  
  	for (forward  = 0 ; forward <= 1 ; forward++) {
--- 315,320 ----
***************
*** 333,356 ****
  			if (pclust == NULL) {
  				break;			/* no page */
  			}
- 			/* handle active pages */
- 			/* NOTE: inactive pages don't have pmap mappings */
- 			if ((pclust->pqflags & PQ_INACTIVE) == 0) {
- 				if ((flags & PGO_DOACTCLUST) == 0) {
- 					/* dont want mapped pages at all */
- 					break;
- 				}
  
! 				/* make sure "clean" bit is sync'd */
! 				if ((pclust->flags & PG_CLEANCHK) == 0) {
! 					if ((pclust->flags & (PG_CLEAN|PG_BUSY))
! 					   == PG_CLEAN &&
! 					   pmap_is_modified(pclust))
! 						pclust->flags &= ~PG_CLEAN;
  
! 					/* now checked */
! 					pclust->flags |= PG_CLEANCHK;
! 				}
  			}
  
  			/* is page available for cleaning and does it need it */
--- 328,355 ----
  			if (pclust == NULL) {
  				break;			/* no page */
  			}
  
! 			if ((flags & PGO_DOACTCLUST) == 0) {
! 				/* dont want mapped pages at all */
! 				break;
! 			}
! 
! 			/*
! 			 * get an up-to-date view of the "clean" bit.
! 			 * note this isn't 100% accurate, but it doesn't
! 			 * have to be.  if it's not quite right, the
! 			 * worst that happens is we don't cluster as
! 			 * aggressively.  we'll sync-it-for-sure before
! 			 * we free the page, and clean it if necessary.
! 			 */
! 			if ((pclust->flags & PG_CLEANCHK) == 0) {
! 				if ((pclust->flags & (PG_CLEAN|PG_BUSY))
! 				    == PG_CLEAN &&
! 				   pmap_is_modified(pclust))
! 					pclust->flags &= ~PG_CLEAN;
  
! 				/* now checked */
! 				pclust->flags |= PG_CLEANCHK;
  			}
  
  			/* is page available for cleaning and does it need it */
Index: uvm_pdaemon.c
===================================================================
RCS file: /cvsroot/syssrc/sys/uvm/uvm_pdaemon.c,v
retrieving revision 1.28
diff -c -r1.28 uvm_pdaemon.c
*** uvm_pdaemon.c	2001/01/25 00:24:48	1.28
--- uvm_pdaemon.c	2001/01/26 19:19:00
***************
*** 533,542 ****
  
  			/*
  			 * we now have the object and the page queues locked.
! 			 * the page is not busy.   if the page is clean we
! 			 * can free it now and continue.
  			 */
  
  			if (p->flags & PG_CLEAN) {
  				if (p->pqflags & PQ_SWAPBACKED) {
  					/* this page now lives only in swap */
--- 533,548 ----
  
  			/*
  			 * we now have the object and the page queues locked.
! 			 * the page is not busy.  remove all the permissions
! 			 * from the page so we can sync the modified info
! 			 * without any race conditions.  if the page is clean
! 			 * we can free it now and continue.
  			 */
  
+ 			pmap_page_protect(p, VM_PROT_NONE);
+ 			if ((p->flags & PG_CLEAN) != 0 && pmap_is_modified(p))
+ 				p->flags &= ~PG_CLEAN;
+ 
  			if (p->flags & PG_CLEAN) {
  				if (p->pqflags & PQ_SWAPBACKED) {
  					/* this page now lives only in swap */
***************
*** 1105,1111 ****
  
  		if (inactive_shortage > 0 &&
  		    pmap_clear_reference(p) == FALSE) {
- 			pmap_page_protect(p, VM_PROT_NONE);
  			/* no need to check wire_count as pg is "active" */
  			uvm_pagedeactivate(p);
  			uvmexp.pddeact++;
--- 1111,1116 ----
Index: uvm_vnode.c
===================================================================
RCS file: /cvsroot/syssrc/sys/uvm/uvm_vnode.c,v
retrieving revision 1.41
diff -c -r1.41 uvm_vnode.c
*** uvm_vnode.c	2001/01/08 06:21:13	1.41
--- uvm_vnode.c	2001/01/26 19:19:01
***************
*** 540,546 ****
  			 */
  			if ((pp->flags & PG_CLEAN) != 0 && 
  			    (flags & PGO_FREE) != 0 &&
! 			    (pp->pqflags & PQ_ACTIVE) != 0)
  				pmap_page_protect(pp, VM_PROT_NONE);
  			if ((pp->flags & PG_CLEAN) != 0 &&
  			    pmap_is_modified(pp))
--- 540,547 ----
  			 */
  			if ((pp->flags & PG_CLEAN) != 0 && 
  			    (flags & PGO_FREE) != 0 &&
! 			    /* XXX ACTIVE|INACTIVE test unnecessary? */
! 			    (pp->pqflags & (PQ_ACTIVE|PQ_INACTIVE)) != 0)
  				pmap_page_protect(pp, VM_PROT_NONE);
  			if ((pp->flags & PG_CLEAN) != 0 &&
  			    pmap_is_modified(pp))
***************
*** 564,570 ****
  				if ((pp->pqflags & PQ_INACTIVE) == 0 &&
  				    (pp->flags & PG_BUSY) == 0 &&
  				    pp->wire_count == 0) {
! 					pmap_page_protect(pp, VM_PROT_NONE);
  					uvm_pagedeactivate(pp);
  				}
  
--- 565,571 ----
  				if ((pp->pqflags & PQ_INACTIVE) == 0 &&
  				    (pp->flags & PG_BUSY) == 0 &&
  				    pp->wire_count == 0) {
! 					pmap_clear_reference(pp);
  					uvm_pagedeactivate(pp);
  				}
  
***************
*** 756,762 ****
  				if ((pp->pqflags & PQ_INACTIVE) == 0 &&
  				    (pp->flags & PG_BUSY) == 0 &&
  				    pp->wire_count == 0) {
! 					pmap_page_protect(ptmp, VM_PROT_NONE);
  					uvm_pagedeactivate(ptmp);
  				}
  			} else if (flags & PGO_FREE) {
--- 757,763 ----
  				if ((pp->pqflags & PQ_INACTIVE) == 0 &&
  				    (pp->flags & PG_BUSY) == 0 &&
  				    pp->wire_count == 0) {
! 					pmap_clear_reference(ptmp);
  					uvm_pagedeactivate(ptmp);
  				}
  			} else if (flags & PGO_FREE) {