Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F105968231
D13346.id36196.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D13346.id36196.diff
View Options
Index: vm/vm_map.c
===================================================================
--- vm/vm_map.c
+++ vm/vm_map.c
@@ -132,6 +132,9 @@
static int vm_map_zinit(void *mem, int ize, int flags);
static void _vm_map_init(vm_map_t map, pmap_t pmap, vm_offset_t min,
vm_offset_t max);
+static int vm_map_alignspace(vm_map_t map, vm_object_t object,
+ vm_ooffset_t offset, vm_offset_t *addr, vm_size_t length,
+ vm_offset_t max_addr, vm_offset_t alignment);
static void vm_map_entry_deallocate(vm_map_entry_t entry, boolean_t system_map);
static void vm_map_entry_dispose(vm_map_t map, vm_map_entry_t entry);
static void vm_map_entry_unwire(vm_map_t map, vm_map_entry_t entry);
@@ -1484,6 +1487,70 @@
}
/*
+ * Searches for the specified amount of free space in the given map with the
+ * specified alignment. Performs an address-ordered, first-fit search from
+ * the given address "*addr", with an optional upper bound "max_addr". If the
+ * parameter "alignment" is zero, then the alignment is computed from the
+ * given (object, offset) pair so as to enable the greatest possible use of
+ * superpage mappings. Returns KERN_SUCCESS and the address of the free space
+ * in "*addr" if successful. Otherwise, returns KERN_NO_SPACE.
+ *
+ * The map must be locked. Initially, there must be at least "length" bytes
+ * of free space at the given address.
+ */
+static int
+vm_map_alignspace(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
+ vm_offset_t *addr, vm_size_t length, vm_offset_t max_addr,
+ vm_offset_t alignment)
+{
+ vm_offset_t aligned_addr, free_addr;
+
+ VM_MAP_ASSERT_LOCKED(map);
+ free_addr = *addr;
+ KASSERT(!vm_map_findspace(map, free_addr, length, addr) &&
+ free_addr == *addr, ("caller provided insufficient free space"));
+ for (;;) {
+ /*
+ * At the start of every iteration, the free space at address
+ * "*addr" is at least "length" bytes.
+ */
+ if (alignment == 0)
+ pmap_align_superpage(object, offset, addr, length);
+ else if ((*addr & (alignment - 1)) != 0) {
+ *addr &= ~(alignment - 1);
+ *addr += alignment;
+ }
+ aligned_addr = *addr;
+ if (aligned_addr == free_addr) {
+ /*
+ * Alignment did not change "*addr", so "*addr" must
+ * still provide sufficient free space.
+ */
+ return (KERN_SUCCESS);
+ }
+
+ /*
+ * Test for address wrap on "*addr". A wrapped "*addr" could
+ * be a valid address, in which case vm_map_findspace() cannot
+ * be relied upon to fail.
+ */
+ if (aligned_addr < free_addr ||
+ vm_map_findspace(map, aligned_addr, length, addr) ||
+ (max_addr != 0 && *addr + length > max_addr))
+ return (KERN_NO_SPACE);
+ free_addr = *addr;
+ if (free_addr == aligned_addr) {
+ /*
+ * If a successful call to vm_map_findspace() did not
+ * change "*addr", then "*addr" must still be aligned
+ * and provide sufficient free space.
+ */
+ return (KERN_SUCCESS);
+ }
+ }
+}
+
+/*
* vm_map_find finds an unallocated region in the target address
* map with the given length. The search is defined to be
* first-fit from the specified address; the region found is
@@ -1498,8 +1565,8 @@
vm_size_t length, vm_offset_t max_addr, int find_space,
vm_prot_t prot, vm_prot_t max, int cow)
{
- vm_offset_t alignment, initial_addr, start;
- int result;
+ vm_offset_t alignment, min_addr;
+ int rv;
KASSERT((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) == 0 ||
object == NULL,
@@ -1512,50 +1579,35 @@
alignment = (vm_offset_t)1 << (find_space >> 8);
} else
alignment = 0;
- initial_addr = *addr;
vm_map_lock(map);
+ if (find_space != VMFS_NO_SPACE) {
+ min_addr = *addr;
again:
- start = initial_addr;
- do {
- if (find_space != VMFS_NO_SPACE) {
- if (vm_map_findspace(map, start, length, addr) ||
- (max_addr != 0 && *addr + length > max_addr)) {
- if (find_space == VMFS_OPTIMAL_SPACE) {
- find_space = VMFS_ANY_SPACE;
- goto again;
- }
- vm_map_unlock(map);
- return (KERN_NO_SPACE);
+ if (vm_map_findspace(map, min_addr, length, addr) ||
+ (max_addr != 0 && *addr + length > max_addr)) {
+ rv = KERN_NO_SPACE;
+ goto done;
+ }
+ if (find_space != VMFS_ANY_SPACE &&
+ (rv = vm_map_alignspace(map, object, offset, addr, length,
+ max_addr, alignment)) != KERN_SUCCESS) {
+ if (find_space == VMFS_OPTIMAL_SPACE) {
+ find_space = VMFS_ANY_SPACE;
+ goto again;
}
- switch (find_space) {
- case VMFS_SUPER_SPACE:
- case VMFS_OPTIMAL_SPACE:
- pmap_align_superpage(object, offset, addr,
- length);
- break;
- case VMFS_ANY_SPACE:
- break;
- default:
- if ((*addr & (alignment - 1)) != 0) {
- *addr &= ~(alignment - 1);
- *addr += alignment;
- }
- break;
- }
-
- start = *addr;
+ goto done;
}
- if ((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) != 0) {
- result = vm_map_stack_locked(map, start, length,
- sgrowsiz, prot, max, cow);
- } else {
- result = vm_map_insert(map, object, offset, start,
- start + length, prot, max, cow);
- }
- } while (result == KERN_NO_SPACE && find_space != VMFS_NO_SPACE &&
- find_space != VMFS_ANY_SPACE);
+ }
+ if ((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) != 0) {
+ rv = vm_map_stack_locked(map, *addr, length, sgrowsiz, prot,
+ max, cow);
+ } else {
+ rv = vm_map_insert(map, object, offset, *addr, *addr + length,
+ prot, max, cow);
+ }
+done:
vm_map_unlock(map);
- return (result);
+ return (rv);
}
int
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Dec 24, 6:08 AM (16 h, 18 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15585933
Default Alt Text
D13346.id36196.diff (5 KB)
Attached To
Mode
D13346: Handle address wrap errors in vm_map_find()
Attached
Detach File
Event Timeline
Log In to Comment