Subject: Problem with uvm_loan-breaking faults
To: None <tech-kern@netbsd.org>
From: Jason R Thorpe <thorpej@wasabisystems.com>
List: tech-kern
Date: 08/28/2002 22:50:48
--zx4FCpZtqtKETZ7O
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Today I was testing some application software which mmap's chunks
of a large file and blasts them out onto the network (and is thus
using zero-copy socket writes).

After a while of the testsuite running, the system would crash with an
assertion failure in the pagedaemon -- the page was on the ACTIVE queue,
but was referenced by neither an object nor an anon, and had a loan_count
of 1.

I tracked this down to being a problem when a loan-breaking fault (a
write fault, which causes the page to be COW'd) happens; the page is
removed from the lender (in this case, a vnode object) and, being an
O->K loan, becomes an orphan, destined to be freed when the kernel is
finished with the page.

The problem is that, in this scenario, the page needs to be removed from
any pageq's it might be on.  A similar situation exists for A->K loans
which are broken by a fault.

The following patch seems to fix it for me ... does this look right?
Note the diffs are relative to the nathanw_sa branch, but the line
numbers should be about the same.

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

--zx4FCpZtqtKETZ7O
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=uvm-loan-patch

Index: uvm_fault.c
===================================================================
RCS file: /cvsroot/syssrc/sys/uvm/uvm_fault.c,v
retrieving revision 1.56.2.11
diff -c -r1.56.2.11 uvm_fault.c
*** uvm_fault.c	2002/07/12 01:40:42	1.56.2.11
--- uvm_fault.c	2002/08/29 05:43:37
***************
*** 1091,1102 ****
  				pmap_page_protect(anon->u.an_page,
  						  VM_PROT_NONE);
  				uvm_lock_pageq();	  /* KILL loan */
! 				if (uobj)
! 					/* if we were loaning */
! 					anon->u.an_page->loan_count--;
  				anon->u.an_page->uanon = NULL;
  				/* in case we owned */
  				anon->u.an_page->pqflags &= ~PQ_ANON;
  				uvm_unlock_pageq();
  				if (uobj) {
  					simple_unlock(&uobj->vmobjlock);
--- 1091,1112 ----
  				pmap_page_protect(anon->u.an_page,
  						  VM_PROT_NONE);
  				uvm_lock_pageq();	  /* KILL loan */
! 
  				anon->u.an_page->uanon = NULL;
  				/* in case we owned */
  				anon->u.an_page->pqflags &= ~PQ_ANON;
+ 
+ 				if (uobj) {
+ 					/* if we were receiver of loan */
+ 					anon->u.an_page->loan_count--;
+ 				} else {
+ 					/*
+ 					 * we were the lender (A->K); need
+ 					 * to remove the page from pageq's.
+ 					 */
+ 					uvm_pagedequeue(anon->u.an_page);
+ 				}
+ 
  				uvm_unlock_pageq();
  				if (uobj) {
  					simple_unlock(&uobj->vmobjlock);
Index: uvm_page.c
===================================================================
RCS file: /cvsroot/syssrc/sys/uvm/uvm_page.c,v
retrieving revision 1.50.2.12
diff -c -r1.50.2.12 uvm_page.c
*** uvm_page.c	2002/08/01 02:47:09	1.50.2.12
--- uvm_page.c	2002/08/29 05:43:38
***************
*** 1186,1191 ****
--- 1186,1202 ----
  		pg->offset = newoff;
  		uvm_pageinsert(pg);
  	}
+ 
+ 	/*
+ 	 * if the page was loaned and no longer referenced by an object
+ 	 * or anon (e.g. if we're breaking an O->K loan), then remove it
+ 	 * from any page queues it was on.
+ 	 */
+ 
+ 	if (pg->loan_count != 0 && pg->uobject == NULL &&
+ 	    pg->uanon == NULL) {
+ 		uvm_pagedequeue(pg);
+ 	}
  }
  
  /*

--zx4FCpZtqtKETZ7O--