Subject: Re: found anoncvs problem . . .
To: Chuck Cranor <chuck@maria.wustl.edu>
From: Jason Thorpe <thorpej@nas.nasa.gov>
List: port-m68k
Date: 12/04/1995 23:12:02
On Mon, 4 Dec 95 21:58:15 CST 
 Chuck Cranor <chuck@maria.wustl.edu> wrote:

 >     it seems to me that we need to somehow limit maxproc to be
 > less than or equal to sizeof(pt_map)/sizeof(user page table) to
 > avoid this hang, in the general case.  where should this be done?
 > comments?   

Chuck, as you and I discussed privately, I'd much rather have fork() 
return EAGAIN than just see and random hang.  "Truncating" seems to be 
safe; it's used to initialize some hash tables, etc., but then, AFAICT, 
is basically only used to check if fork() should fail.  Seeing as how 
sysctl(2) can raise it, I certainly think it should be safe for 
pmap_init() to lower it.  Attached below is the patch I plan on 
committing to the NetBSD/hp300 pmap.c unless someone else has a better 
idea that's relatively feasible.  (Note, I have a pending PR on this 
that's O(1.5 years) old, so I'm somewhat motivated to get some sort of fix 
into the tree :-).

Index: pmap.c
===================================================================
RCS file: /usr/og/devsrc/netbsd/src/sys/arch/hp300/hp300/pmap.c,v
retrieving revision 1.1.1.3
diff -c -r1.1.1.3 pmap.c
*** pmap.c	1995/10/09 21:32:58	1.1.1.3
--- pmap.c	1995/12/04 03:22:39
***************
*** 457,463 ****
  	 * map where we want it.
  	 */
  	addr = HP_PTBASE;
! 	s = min(HP_PTMAXSIZE, maxproc*HP_MAX_PTSIZE);
  	addr2 = addr + s;
  	rv = vm_map_find(kernel_map, NULL, 0, &addr, s, TRUE);
  	if (rv != KERN_SUCCESS)
--- 457,473 ----
  	 * map where we want it.
  	 */
  	addr = HP_PTBASE;
! 	if ((HP_PTMAXSIZE / HP_MAX_PTSIZE) < maxproc) {
! 		s = HP_PTMAXSIZE;
! 		/*
! 		 * XXX We don't want to hang when we run out of
! 		 * page tables, so we lower maxproc so that fork()
! 		 * will fail instead.  Note that root could still raise
! 		 * this value via sysctl(2).
! 		 */
! 		maxproc = (HP_PTMAXSIZE / HP_MAX_PTSIZE);
! 	} else
! 		s = (maxproc * HP_MAX_PTSIZE);
  	addr2 = addr + s;
  	rv = vm_map_find(kernel_map, NULL, 0, &addr, s, TRUE);
  	if (rv != KERN_SUCCESS)

I would suggest that each port declare a MAXMAXPROC for param.h so that 
sysctl(2) would have an upper bound.

I've run this on my hp380 and hp319, and ran a fork-bomb on both.  It 
appeared to do the right thing ... the fork failed before everything 
wedged.  The bomb basically did the following:

 top:
	if fork fails
		exit with error message;

	if parent
		wait for child to exit;
	else {
		malloc NBPG
		bzero page
		goto top;
	}

I don't particularly like the idea of arbitrarily limiting a processes' 
vmspace, so the above patch seems like a reasonable solution, at least 
until something better can be found.

--------------------------------------------------------------------------
Jason R. Thorpe                                       thorpej@nas.nasa.gov
NASA Ames Research Center                               Home: 408.866.1912
NAS: M/S 258-6                                          Work: 415.604.0935
Moffett Field, CA 94035                                Pager: 415.428.6939