If vm_map_find() is asked to allocate a superpage-aligned region of virtual
addresses that is greater than a superpage in size but not a multiple of the superpage size, then vm_map_find() is not always expanding the kernel pmap to support the last few small pages being allocated. These failures are not commonplace, so this was first noticed by someone porting FreeBSD to a new architecture. Previously, we grew the kernel page table in vm_map_findspace() when we found the first available virtual address. This works most of the time because we always grow the kernel pmap or page table by an amount that is a multiple of the superpage size. Now, instead, we defer the call to pmap_growkernel() until we are committed to a range of virtual addresses in vm_map_insert(). In general, there is another reason to prefer calling pmap_growkernel() in vm_map_insert(). It makes it possible for someone to do the equivalent of an mmap(MAP_FIXED) on the kernel map. Reported by: Svatopluk Kraus Reviewed by: kib@ MFC after: 3 weeks
This commit is contained in:
parent
94363f5311
commit
f8616ebfae
@ -1163,6 +1163,9 @@ vm_map_insert(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
|
||||
}
|
||||
|
||||
charged:
|
||||
/* Expand the kernel pmap, if necessary. */
|
||||
if (map == kernel_map && end > kernel_vm_end)
|
||||
pmap_growkernel(end);
|
||||
if (object != NULL) {
|
||||
/*
|
||||
* OBJ_ONEMAPPING must be cleared unless this mapping
|
||||
@ -1299,7 +1302,7 @@ vm_map_findspace(vm_map_t map, vm_offset_t start, vm_size_t length,
|
||||
vm_offset_t *addr) /* OUT */
|
||||
{
|
||||
vm_map_entry_t entry;
|
||||
vm_offset_t end, st;
|
||||
vm_offset_t st;
|
||||
|
||||
/*
|
||||
* Request must fit within min/max VM address and must avoid
|
||||
@ -1313,7 +1316,7 @@ vm_map_findspace(vm_map_t map, vm_offset_t start, vm_size_t length,
|
||||
/* Empty tree means wide open address space. */
|
||||
if (map->root == NULL) {
|
||||
*addr = start;
|
||||
goto found;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1323,7 +1326,7 @@ vm_map_findspace(vm_map_t map, vm_offset_t start, vm_size_t length,
|
||||
map->root = vm_map_entry_splay(start, map->root);
|
||||
if (start + length <= map->root->start) {
|
||||
*addr = start;
|
||||
goto found;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1334,7 +1337,7 @@ vm_map_findspace(vm_map_t map, vm_offset_t start, vm_size_t length,
|
||||
st = (start > map->root->end) ? start : map->root->end;
|
||||
if (length <= map->root->end + map->root->adj_free - st) {
|
||||
*addr = st;
|
||||
goto found;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* With max_free, can immediately tell if no solution. */
|
||||
@ -1352,22 +1355,13 @@ vm_map_findspace(vm_map_t map, vm_offset_t start, vm_size_t length,
|
||||
entry = entry->left;
|
||||
else if (entry->adj_free >= length) {
|
||||
*addr = entry->end;
|
||||
goto found;
|
||||
return (0);
|
||||
} else
|
||||
entry = entry->right;
|
||||
}
|
||||
|
||||
/* Can't get here, so panic if we do. */
|
||||
panic("vm_map_findspace: max_free corrupt");
|
||||
|
||||
found:
|
||||
/* Expand the kernel pmap, if necessary. */
|
||||
if (map == kernel_map) {
|
||||
end = round_page(*addr + length);
|
||||
if (end > kernel_vm_end)
|
||||
pmap_growkernel(end);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
|
Loading…
Reference in New Issue
Block a user