*BSD News Article 10243


Return to BSD News archive

Received: by minnie.vk1xwt.ampr.org with NNTP
	id AA7546 ; Fri, 22 Jan 93 16:00:47 EST
Path: sserve!manuel.anu.edu.au!dubhe.anu.edu.au!sirius.anu.edu.au!not-for-mail
From: paulus@cs.anu.edu.au (Paul Mackerras)
Newsgroups: comp.unix.bsd
Subject: Bug + fix: page leak in VM system
Date: 22 Jan 1993 15:19:37 +1100
Organization: Computer Science Department, ANU, Australia
Lines: 74
Message-ID: <1jnskpINN2a0@sirius.anu.edu.au>
NNTP-Posting-Host: sirius.anu.edu.au
Keywords: VM system, bug, memory leak

I have found a bug in the new Mach-derived VM system in BSD Unix (as
in the NET/2 release and 386BSD) which causes it to lose physical
pages, resulting in less memory for running programs and increased
likelihood of thrashing.

The bug is that the call to vm_page_deactivate() at line 531 of
vm_fault.c does not put the (now no longer needed) page back on the
inactive list, because vm_page_deactivate() only does anything with
active pages.  Consequently, the page is then not on the active,
inactive or free lists and is effectively not available for use.  (It
is not lost forever, though, because it is still on its object's page
queue.)

The situation where this occurs is basically the following:
	1. A process has a copy-on-write mapping, e.g. to the data
	   segment of an executable file.
	2. The process reads a page in the copy-on-write region.
	   The VM system allocates a page and reads in the data from
	   the file.
	3. The process writes to the page.  The VM system allocates
	   a second page, copies the first page to it, and then
	   loses the first page :-(.

The following patch corrects the problem.

Paul Mackerras
Dept. Computer Science,
Australian National University.
paulus@cs.anu.edu.au

-----------------------------------------------------------------------------
*** vm_page-orig.c	Fri Jan 22 09:54:01 1993
--- vm_page.c	Fri Jan 22 09:52:51 1993
***************
*** 687,701 ****
  	/*
  	 *	Only move active pages -- ignore locked or already
  	 *	inactive ones.
  	 */
  
! 	if (m->active) {
  		pmap_clear_reference(VM_PAGE_TO_PHYS(m));
! 		queue_remove(&vm_page_queue_active, m, vm_page_t, pageq);
  		queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq);
- 		m->active = FALSE;
  		m->inactive = TRUE;
- 		vm_page_active_count--;
  		vm_page_inactive_count++;
  		if (pmap_is_modified(VM_PAGE_TO_PHYS(m)))
  			m->clean = FALSE;
--- 687,708 ----
  	/*
  	 *	Only move active pages -- ignore locked or already
  	 *	inactive ones.
+ 	 *
+ 	 *	XXX: sometimes we get pages which aren't wired down
+ 	 *	or on any queue - we need to put them on the inactive
+ 	 *	queue also, otherwise we lose track of them.
+ 	 *	Paul Mackerras (paulus@cs.anu.edu.au) 9-Jan-93.
  	 */
  
! 	if (!m->inactive && m->wire_count == 0) {
  		pmap_clear_reference(VM_PAGE_TO_PHYS(m));
! 		if (m->active) {
! 			queue_remove(&vm_page_queue_active, m, vm_page_t, pageq);
! 			m->active = FALSE;
! 			vm_page_active_count--;
! 		}
  		queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq);
  		m->inactive = TRUE;
  		vm_page_inactive_count++;
  		if (pmap_is_modified(VM_PAGE_TO_PHYS(m)))
  			m->clean = FALSE;