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 ; 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 ; 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 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 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 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: