mlockall(2 fixed

From: Brian Fundakowski Feldman <green_at_FreeBSD.org>
Date: Tue, 27 Apr 2004 18:54:37 -0400
Please try the following if you are having strange SIGBUS problems/leaked 
wired memory and you are running programs that use mlockall(2).  There were 
several distinct bugs that caused pages to never get unwired and completely 
unrelated processes to act as if mlockall(2) was called when they had not 
done so.

Index: vm_fault.c
===================================================================
RCS file: /usr/ncvs/src/sys/vm/vm_fault.c,v
retrieving revision 1.186
diff -u -r1.186 vm_fault.c
--- vm_fault.c	10 Mar 2004 04:44:43 -0000	1.186
+++ vm_fault.c	27 Apr 2004 21:45:53 -0000
_at__at_ -1065,6 +1065,14 _at__at_
 	return (KERN_SUCCESS);
 }
 
+SYSCTL_NODE(_vm, OID_AUTO, fault_unwire, CTLFLAG_RW, 0, "vm_fault_unwire");
+static unsigned int vm_fault_unwire_noentry;
+SYSCTL_UINT(_vm_fault_unwire, OID_AUTO, noentry,
+	CTLFLAG_RD, &vm_fault_unwire_noentry, 0, "");
+static unsigned int vm_fault_unwire_nopage;
+SYSCTL_UINT(_vm_fault_unwire, OID_AUTO, nopage,
+	CTLFLAG_RD, &vm_fault_unwire_nopage, 0, "");
+
 /*
  *	vm_fault_unwire:
  *
_at__at_ -1075,28 +1083,56 _at__at_
 	vm_map_t map;
 	vm_offset_t start, end;
 {
-	vm_paddr_t pa;
+	vm_map_entry_t entry;
+	vm_object_t object, object2;
 	vm_offset_t va;
+	vm_page_t page;
+	vm_ooffset_t oidx;
 	pmap_t pmap;
 
 	pmap = vm_map_pmap(map);
-
-	if (pmap != kernel_pmap)
+	if (!map->system_map)
 		mtx_lock(&Giant);
-	/*
-	 * Since the pages are wired down, we must be able to get their
-	 * mappings from the physical map system.
-	 */
-	for (va = start; va < end; va += PAGE_SIZE) {
-		pa = pmap_extract(pmap, va);
-		if (pa != 0) {
-			pmap_change_wiring(pmap, va, FALSE);
+	for (entry = NULL, va = start; va < end; va += PAGE_SIZE) {
+		if (entry == NULL || va >= entry->end) {
+			if (vm_map_lookup_entry(map, va, &entry) == FALSE) {
+				atomic_add_int(&vm_fault_unwire_noentry, 1);
+				entry = NULL;
+				continue;
+			}
+		}
+		object = entry->object.vm_object;
+		oidx = OFF_TO_IDX(entry->offset + va - entry->start);
+		VM_OBJECT_LOCK(object);
+nextobject:
+		page = vm_page_lookup(object, oidx);
+		if (page != NULL) {
+			/*
+			 * The page itself may be wired, but if it was
+			 * never accessed from anything other than
+			 * vm_fault_prefault(), it won't exist in pmap.
+			 */
+			if (pmap_extract(pmap, va) != 0)
+				pmap_change_wiring(pmap, va, FALSE);
 			vm_page_lock_queues();
-			vm_page_unwire(PHYS_TO_VM_PAGE(pa), 1);
+			vm_page_unwire(page, 1);
 			vm_page_unlock_queues();
+		} else {
+			object2 = object->backing_object;
+			if (object2 == NULL) {
+				atomic_add_int(&vm_fault_unwire_nopage, 1);
+			} else {
+				VM_OBJECT_LOCK(object2);
+				oidx +=
+				   OFF_TO_IDX(object->backing_object_offset);
+				VM_OBJECT_UNLOCK(object);
+				object = object2;
+				goto nextobject;
+			}
 		}
+		VM_OBJECT_UNLOCK(object);
 	}
-	if (pmap != kernel_pmap)
+	if (!map->system_map)
 		mtx_unlock(&Giant);
 }
 
Index: vm_map.c
===================================================================
RCS file: /usr/ncvs/src/sys/vm/vm_map.c,v
retrieving revision 1.332
diff -u -r1.332 vm_map.c
--- vm_map.c	6 Apr 2004 20:15:36 -0000	1.332
+++ vm_map.c	27 Apr 2004 22:43:58 -0000
_at__at_ -297,6 +297,7 _at__at_
 	vm_map_lock(&vm->vm_map);
 	(void) vm_map_delete(&vm->vm_map, vm->vm_map.min_offset,
 	    vm->vm_map.max_offset);
+	vm_map_modflags(&vm->vm_map, 0, MAP_WIREFUTURE);
 	vm_map_unlock(&vm->vm_map);
 
 	pmap_release(vmspace_pmap(vm));


-- 
Brian Fundakowski Feldman                           \'[ FreeBSD ]''''''''''\
  <> green_at_FreeBSD.org                               \  The Power to Serve! \
 Opinions expressed are my own.                       \,,,,,,,,,,,,,,,,,,,,,,\
Received on Tue Apr 27 2004 - 13:54:39 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:37:52 UTC