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;