mlockall(2 fixed

Brian Fundakowski Feldman green at FreeBSD.org
Tue Apr 27 15:54:39 PDT 2004


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
@@ -1065,6 +1065,14 @@
 	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:
  *
@@ -1075,28 +1083,56 @@
 	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
@@ -297,6 +297,7 @@
 	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.                       \,,,,,,,,,,,,,,,,,,,,,,\




More information about the freebsd-current mailing list