From Tor.Egge@idt.ntnu.no  Thu Jan  9 05:47:24 1997
Received: from pat.idt.unit.no (0@pat.idt.unit.no [129.241.103.5])
          by freefall.freebsd.org (8.8.4/8.8.4) with ESMTP id FAA29774
          for <FreeBSD-gnats-submit@freebsd.org>; Thu, 9 Jan 1997 05:47:23 -0800 (PST)
Received: from ikke.idt.unit.no (tegge@ikke.idt.unit.no [129.241.111.65])
          by pat.idt.unit.no (8.8.4/8.8.4) with ESMTP
	  id OAA08621 for <FreeBSD-gnats-submit@freebsd.org>; Thu, 9 Jan 1997 14:47:18 +0100 (MET)
Received: (from tegge@localhost) by ikke.idt.unit.no (8.8.4/8.8.3) id OAA01381; Thu, 9 Jan 1997 14:47:17 +0100 (MET)
Message-Id: <199701091347.OAA01381@ikke.idt.unit.no>
Date: Thu, 9 Jan 1997 14:47:17 +0100 (MET)
From: Tor Egge <Tor.Egge@idt.ntnu.no>
Reply-To: Tor.Egge@idt.ntnu.no
To: FreeBSD-gnats-submit@freebsd.org
Subject: panic: get_pv_entry: cannot get a pv_entry_t
X-Send-Pr-Version: 3.2

>Number:         2431
>Category:       i386
>Synopsis:       panic: get_pv_entry: cannot get a pv_entry_t
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    tegge
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jan  9 05:50:01 PST 1997
>Closed-Date:    Mon Sep  7 12:32:34 1998
>Last-Modified:  Mon Sep  7 12:37:50 PDT 1998
>Originator:     Tor Egge
>Release:        FreeBSD 3.0-CURRENT i386
>Organization:
Norwegian University of Science and Technology, Trondheim, Norway
>Environment:

FreeBSD ikke.idt.unit.no 3.0-CURRENT FreeBSD 3.0-CURRENT #0: Fri Jan  3 16:55:28 MET 1997     root@ikke.idt.unit.no:/usr/src/sys-UP/compile/TEGGE  i386

	512 MB memory

>Description:

	When a process with a lot of resident memory (>300 MB, where
	180 MB is mlocked) forks while the amount of free physical 
	memory is low, the system may run out of free memory when 
	allocating elements of type pv_entry_t.

	When attempting to dump the memory to the dump device, the
	system tries to allocate even more elements of type pv_entry_t,
	causing a recursive panic, and no dump.
	
>How-To-Repeat:

	See above.

>Fix:

Workaround:

Use sysctl to increase limits of reserved free physical memory, reducing the 
probability for running out of free memory.

e.g.
	sysctl -w vm.v_free_reserved=1024
	sysctl -w vm.v_free_min=1500
>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->feedback 
State-Changed-By: steve 
State-Changed-When: Sat May 30 18:02:59 PDT 1998 
State-Changed-Why:  
Tor do you still see this problem?  If so, can you take a swack 
at it since you are committer now? 

From: Studded <Studded@san.rr.com>
To: freebsd-gnats-submit@freebsd.org, Tor.Egge@idt.ntnu.no
Cc:  Subject: Re: i386/2431: panic: get_pv_entry: cannot get a pv_entry_t
Date: Sun, 31 May 1998 16:43:18 -0700

 I am seeing this problem regularly on a 2.2.2-Release system with 256M
 of physical ram dedicated to a single process that regularly demands
 200M. 
 
 Doug
State-Changed-From-To: feedback->open 
State-Changed-By: steve 
State-Changed-When: Thu Jun 4 21:03:11 PDT 1998 
State-Changed-Why:  
Doug White says this still occurs. 


Responsible-Changed-From-To: freebsd-bugs->tegge 
Responsible-Changed-By: steve 
Responsible-Changed-When: Thu Jun 4 21:03:11 PDT 1998 
Responsible-Changed-Why:  
Hopefully now that Tor is a committer he will champion this 
PR since he orginated it. :) 

From: josh <josh@lucratec.com>
To: freebsd-gnats-submit@freebsd.org, Tor.Egge@idt.ntnu.no
Cc:  Subject: Re: i386/2431: panic: get_pv_entry: cannot get a pv_entry_t
Date: Sat, 04 Jul 1998 03:24:16 -0500

 http://www.freebsd.org/cgi/query-pr.cgi?pr=2431
 
 
 I've ran into this problem running a web server with 512 megs of ram
 running
 2.2.6-STABLE with apache 3.0 stable
 
 The machine has no load other than httpd, and I have atleast 500 httpd
 processes running constantly.
 
 It seems when I get to 700+ httpd processes, I get the
 panic: get_pv_entry: cannot get a pv_entry_t error.
 
 So I use the workarond posted on the above url:
 
 Workaround:
 
      Use sysctl to increase limits of reserved free physical memory,
 reducing the
      probability for running out of free memory.
 
      e.g.
              sysctl -w vm.v_free_reserved=1024
              sysctl -w vm.v_free_min=1500
 
 At the default example it doesn't seem to stop my system from
 panicking.  So I've
 tried doubling and even quadrupling both of those numbers with no
 effects.
 
 
 

From: Tor.Egge@fast.no
To: freebsd-gnats-submit@freebsd.org
Cc:  Subject: Re: i386/2431: panic: get_pv_entry: cannot get a pv_entry_t
Date: Mon, 13 Jul 1998 04:56:11 +0200

 Here is a suggested fix for 2.2.6-STABLE.
 
 This patch contains a backport of pmap_collect from -current (which
 should handle most cases where the value of PMAP_SHPGPERPROC is too
 small), and new code to skip optional work in pmap_copy when the
 number of free pages drops too low or a high water mark of pv_entries
 has been reached.
 
 Index: sys/vm/vm_pageout.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/vm/vm_pageout.c,v
 retrieving revision 1.86.2.2
 diff -u -r1.86.2.2 vm_pageout.c
 --- vm_pageout.c	1997/03/25 04:54:36	1.86.2.2
 +++ vm_pageout.c	1998/07/12 23:30:24
 @@ -172,6 +172,7 @@
  static freeer_fcn_t vm_pageout_object_deactivate_pages;
  static void vm_req_vmdaemon __P((void));
  #endif
 +void pmap_collect(void);
  
  /*
   * vm_pageout_clean:
 @@ -576,6 +577,11 @@
  	int force_wakeup = 0;
  	int vnodes_skipped = 0;
  	int s;
 +
 +	/*
 +	 * Do whatever cleanup that the pmap code can.
 +	 */
 +	pmap_collect();
  
  	/*
  	 * Start scanning the inactive queue for pages we can free. We keep
 Index: sys/i386/i386/pmap.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/i386/i386/pmap.c,v
 retrieving revision 1.128.2.6
 diff -u -r1.128.2.6 pmap.c
 --- pmap.c	1997/06/26 00:05:16	1.128.2.6
 +++ pmap.c	1998/07/13 00:53:40
 @@ -153,6 +153,7 @@
  static boolean_t pmap_initialized = FALSE;	/* Has pmap_init completed? */
  static vm_offset_t vm_first_phys;
  static int pgeflag;		/* PG_G or-in */
 +static int pv_npg;
  
  static int nkpt;
  static vm_page_t nkpg;
 @@ -170,6 +172,8 @@
  TAILQ_HEAD (,pv_entry) pv_freelist = {0};
  static vm_offset_t pvva;
  static int npvvapg;
 +static int pv_entry_count=0, pv_entry_max=0, pv_entry_high_water=0;
 +static int pmap_pagedaemon_waken = 0;
  
  /*
   * All those kernel PT submaps that BSD is so fond of
 @@ -213,6 +217,7 @@
  static vm_page_t pmap_page_alloc __P((vm_object_t object, vm_pindex_t pindex));
  static vm_page_t pmap_page_lookup __P((vm_object_t object, vm_pindex_t pindex));
  static int pmap_unuse_pt __P((pmap_t, vm_offset_t, vm_page_t));
 +void pmap_collect(void);
  
  #define PDSTACKMAX 6
  static vm_offset_t pdstack[PDSTACKMAX];
 @@ -1374,6 +1379,7 @@
  	pv_entry_t pv;
  {
  	++pv_freelistcnt;
 +	pv_entry_count--;
  	TAILQ_INSERT_HEAD(&pv_freelist, pv, pv_list);
  }
  
 @@ -1388,6 +1394,12 @@
  {
  	pv_entry_t tmp;
  
 +	pv_entry_count++;
 +	if ((pv_entry_count > pv_entry_high_water) &&
 +		(pmap_pagedaemon_waken == 0)) {
 +		pmap_pagedaemon_waken = 1;
 +		wakeup (&vm_pages_needed);
 +	}
  	/*
  	 * get more pv_entry pages if needed
  	 */
 @@ -1451,6 +1463,7 @@
  			 * free the entries into the free list
  			 */
  			for (i = 0; i < newentries; i++) {
 +				pv_entry_count++;
  				free_pv_entry(entry);
  				entry++;
  			}
 @@ -1478,8 +1491,11 @@
  	 * we will free other entries (and the associated mappings), with
  	 * some policy yet to be determined.
  	 */
 -	npvvapg = ((PMAP_SHPGPERPROC * maxproc + npg) * sizeof(struct pv_entry)
 -		+ PAGE_SIZE - 1) / PAGE_SIZE;
 +  	pv_npg = npg;
 +	pv_entry_max = PMAP_SHPGPERPROC * maxproc + npg;
 +	pv_entry_high_water = 9 * (pv_entry_max / 10);
 +	npvvapg = (pv_entry_max * sizeof(struct pv_entry)
 +		   + PAGE_SIZE - 1) / PAGE_SIZE;
  	pvva = kmem_alloc_pageable(kernel_map, npvvapg * PAGE_SIZE);
  	/*
  	 * get the first batch of entries
 @@ -1487,6 +1503,41 @@
  	pmap_alloc_pv_entry();
  }
  
 +
 +/*
 + * This routine is very drastic, but can save the system
 + * in a pinch.
 + */
 +void
 +pmap_collect() {
 +	pv_table_t *ppv;
 +	int i;
 +	vm_offset_t pa;
 +	vm_page_t m;
 +	static int warningdone=0;
 +
 +	if (pmap_pagedaemon_waken == 0)
 +		return;
 +
 +	if (warningdone < 5) {
 +		printf("pmap_collect: collecting pv entries -- suggest increasing PMAP_SHPGPERPROC");
 +		warningdone++;
 +	}
 +
 +	for(i = 0; i < pv_npg; i++) {
 +		if ((ppv = &pv_table[i]) == 0)
 +			continue;
 +		m = ppv->pv_vm_page;
 +		if ((pa = VM_PAGE_TO_PHYS(m)) == 0)
 +			continue;
 +		if (m->wire_count || m->hold_count || m->busy || 
 +		    (m->flags & PG_BUSY))
 +			continue;
 +		pmap_remove_all(pa);
 +	}
 +	pmap_pagedaemon_waken = 0;
 +}
 +	
  /*
   * If it is the first entry on the list, it is actually
   * in the header and we must copy the following entry up
 @@ -2397,6 +2452,15 @@
  		if (addr >= UPT_MIN_ADDRESS)
  			panic("pmap_copy: invalid to pmap_copy page tables\n");
  
 +		/*
 +		 * Don't make optional prefaulting of pages make us go
 +		 * way below the low water mark of free pages or way
 +		 * above high water mark of used pv entries.
 +		 */
 +		if (cnt.v_free_count < cnt.v_free_reserved ||
 +		    pv_entry_count > pv_entry_high_water)
 +			break;
 +		
  		pdnxt = ((addr + PAGE_SIZE*NPTEPG) & ~(PAGE_SIZE*NPTEPG - 1));
  		ptepindex = addr >> PDRSHIFT;

State-Changed-From-To: open->closed
State-Changed-By: tegge
State-Changed-When: Mon Sep  7 12:32:34 1998
State-Changed-Why:
Mostly fixed in -current. An additional measure might be to change
default value of cnt.v_interrupt_free_min from 2 to 20 (in vm_pageout.c).
>Unformatted:
