Subject: Re: kern/3249: More vm woes
To: None <scotte@warped.com>
From: Jason Thorpe <thorpej@nas.nasa.gov>
List: netbsd-bugs
Date: 02/25/1997 15:48:04
On Mon, 24 Feb 1997 19:40:51 (-0800) 
 Scott Ellis <scotte@warped.com> wrote:

 > Are you running lpd?  I noticed that using yesterdays vm_object (building
 > a kernel with the new .c file now...) that lpd would cause the system
 > to hang on startup, rather than when it was killed.  Removing lpd from
 > rc.conf solved the problem.

Ok!  More info!

Charles Hannum went searching and found the bug... Here's an explanation
of the bug, supplied by Charles:

	(1) When you do an sbrk(), it creates a map entry with
	    no backing object.  This is expected to be replaced
	    with a zero-filled object when it's first faulted.

	(2) When you fork, that entry gets copied, but the "needs_copy"
	    bit is set.

	(3) If the child then touches those pages before it forks,
	    vm_map_lookup() tries to do a vm_object_shadow() on a null
	    object.  This causes a kernel fault.

	(4) That kernel fault generally points into user space, so
	    the fault handler tries to do another lookup in user
	    space and deadlocks trying to lock the map.

The patch appended below fixes the problem.  I have committed it to
the tree, and will run the SUP scanner shortly.

Ciao!

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

 ----- snip -----

diff -rc2 t/vm_map.c ./vm_map.c
*** t/vm_map.c	Thu Feb 20 10:13:29 1997
--- ./vm_map.c	Mon Feb 24 23:21:44 1997
***************
*** 1770,1776 ****
  		/*
  		 *	The destination always needs to have a shadow
! 		 *	created.
  		 */
! 		dst_entry->needs_copy = TRUE;
  
  		/*
--- 1770,1779 ----
  		/*
  		 *	The destination always needs to have a shadow
! 		 *	created, unless it's a zero-fill entry.
  		 */
! 		if (dst_entry->object.vm_object != NULL)
! 			dst_entry->needs_copy = TRUE;
! 		else
! 			dst_entry->needs_copy = FALSE;
  
  		/*
diff -rc2 t/vm_object.c ./vm_object.c
*** t/vm_object.c	Sun Feb 23 15:22:25 1997
--- ./vm_object.c	Mon Feb 24 23:24:48 1997
***************
*** 897,900 ****
--- 897,905 ----
  	source = *object;
  
+ #ifdef DIAGNOSTIC
+ 	if (source == NULL)
+ 		panic("vm_object_shadow: attempt to shadow null object");
+ #endif
+ 
  	/*
  	 * Allocate a new object with the given length